Skip to content
This repository was archived by the owner on Sep 10, 2023. It is now read-only.

Commit ef201f7

Browse files
committed
fix: fix for loop scope with fork a new scope to resolve it
1 parent 294a645 commit ef201f7

File tree

4 files changed

+128
-106
lines changed

4 files changed

+128
-106
lines changed

src/evaluate.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,21 +314,24 @@ const visitors: EvaluateMap = {
314314
const { node, scope } = path;
315315

316316
// FIXME: for循环的作用域问题
317-
const newScope = scope.createChild("loop").setInvasive(true);
317+
const forScope = scope.createChild("loop");
318318

319-
newScope.invasive = true;
320-
newScope.redeclare = true;
319+
forScope.invasive = true; // 有块级作用域
321320

322321
if (node.init) {
323-
evaluate(path.createChild(node.init, newScope));
322+
evaluate(path.createChild(node.init, forScope));
324323
}
325324

326325
for (;;) {
327-
if (node.test && !evaluate(path.createChild(node.test, newScope))) {
326+
// every loop will create it's own scope
327+
// it should inherit from forScope
328+
const loopScope = forScope.fork();
329+
330+
if (node.test && !evaluate(path.createChild(node.test, forScope))) {
328331
break;
329332
}
330333

331-
const result = evaluate(path.createChild(node.body, newScope));
334+
const result = evaluate(path.createChild(node.body, loopScope));
332335
if (Signal.isBreak(result)) {
333336
break;
334337
} else if (Signal.isContinue(result)) {
@@ -337,7 +340,7 @@ const visitors: EvaluateMap = {
337340
return result;
338341
}
339342
if (node.update) {
340-
evaluate(path.createChild(node.update, newScope));
343+
evaluate(path.createChild(node.update, forScope));
341344
}
342345
}
343346
},

src/scope.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class Scope {
4141
}
4242
}
4343

44-
public all(): { [key: string]: any } {
44+
public raw(): { [key: string]: any } {
4545
const map = {};
4646
for (const varName in this.content) {
4747
if (this.content.hasOwnProperty(varName)) {
@@ -141,4 +141,24 @@ export class Scope {
141141
public createChild(type: ScopeType, label?: string): Scope {
142142
return new Scope(type, this, label);
143143
}
144+
public fork(): Scope {
145+
// forks a new scope
146+
const newScope = new Scope("block", null);
147+
148+
// copy the properties
149+
newScope.invasive = this.invasive;
150+
newScope.redeclare = this.redeclare;
151+
newScope.isTopLevel = this.isTopLevel;
152+
newScope.context = this.context;
153+
newScope.parent = this.parent;
154+
155+
// copy the vars
156+
for (const varName in this.content) {
157+
if (this.content.hasOwnProperty(varName)) {
158+
const $var = this.content[varName];
159+
newScope.declare($var.kind, $var.name, $var.value);
160+
}
161+
}
162+
return newScope;
163+
}
144164
}

src/type.ts

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,89 @@
1-
import * as types from "babel-types";
1+
import * as t from "babel-types";
22
import { Path } from "./path";
33

44
export type ScopeType = "function" | "loop" | "switch" | "block" | "class";
55

66
export type Kind = "const" | "var" | "let";
77

88
export interface INodeTypeMap {
9-
File: types.File;
10-
Program: types.Program;
11-
Identifier: types.Identifier;
12-
NullLiteral: types.NullLiteral;
13-
StringLiteral: types.StringLiteral;
14-
NumericLiteral: types.NumericLiteral;
15-
BooleanLiteral: types.BooleanLiteral;
16-
RegExpLiteral: types.RegExpLiteral;
17-
FunctionDeclaration: types.FunctionDeclaration;
18-
FunctionExpression: types.FunctionExpression;
19-
ArrowFunctionExpression: types.ArrowFunctionExpression;
20-
SwitchCase: types.SwitchCase;
21-
CatchClause: types.CatchClause;
22-
VariableDeclarator: types.VariableDeclarator;
23-
ExpressionStatement: types.ExpressionStatement;
24-
BlockStatement: types.BlockStatement;
25-
EmptyStatement: types.EmptyStatement;
26-
DebuggerStatement: types.DebuggerStatement;
27-
WithStatement: types.WithStatement;
28-
ReturnStatement: types.ReturnStatement;
29-
LabeledStatement: types.LabeledStatement;
30-
BreakStatement: types.BreakStatement;
31-
ContinueStatement: types.ContinueStatement;
32-
IfStatement: types.IfStatement;
33-
SwitchStatement: types.SwitchStatement;
34-
ThrowStatement: types.ThrowStatement;
35-
TryStatement: types.TryStatement;
36-
WhileStatement: types.WhileStatement;
37-
DoWhileStatement: types.DoWhileStatement;
38-
ForStatement: types.ForStatement;
39-
ForInStatement: types.ForInStatement;
40-
ForOfStatement: types.ForOfStatement;
41-
VariableDeclaration: types.VariableDeclaration;
42-
ClassDeclaration: types.ClassDeclaration;
43-
ThisExpression: types.ThisExpression;
44-
ArrayExpression: types.ArrayExpression;
45-
ObjectExpression: types.ObjectExpression;
46-
ObjectProperty: types.ObjectProperty;
47-
ObjectMethod: types.ObjectMethod;
48-
YieldExpression: types.YieldExpression;
49-
UnaryExpression: types.UnaryExpression;
50-
UpdateExpression: types.UpdateExpression;
51-
BinaryExpression: types.BinaryExpression;
52-
AssignmentExpression: types.AssignmentExpression;
53-
LogicalExpression: types.LogicalExpression;
54-
MemberExpression: types.MemberExpression;
55-
ConditionalExpression: types.ConditionalExpression;
56-
CallExpression: types.CallExpression;
57-
NewExpression: types.NewExpression;
58-
SequenceExpression: types.SequenceExpression;
59-
TemplateLiteral: types.TemplateLiteral;
60-
TaggedTemplateExpression: types.TaggedTemplateExpression;
61-
ClassExpression: types.ClassExpression;
62-
ClassMethod: types.ClassMethod;
63-
MetaProperty: types.MetaProperty;
64-
AwaitExpression: types.AwaitExpression;
65-
Super: types.Super;
66-
TemplateElement: types.TemplateElement;
67-
SpreadElement: types.SpreadElement;
68-
// ObjectPattern: types.ObjectPattern;
69-
// ArrayPattern: types.ArrayPattern;
70-
RestElement: types.RestElement;
71-
AssignmentPattern: types.AssignmentPattern;
72-
ClassBody: types.ClassBody;
73-
ImportDeclaration: types.ImportDeclaration;
74-
ExportNamedDeclaration: types.ExportNamedDeclaration;
75-
ExportDefaultDeclaration: types.ExportDefaultDeclaration;
76-
// ExportAllDeclaration: types.ExportAllDeclaration;
77-
ImportSpecifier: types.ImportSpecifier;
78-
ImportDefaultSpecifier: types.ImportDefaultSpecifier;
79-
// ImportNamespaceSpecifier: types.ImportNamespaceSpecifier;
80-
ExportSpecifier: types.ExportSpecifier;
81-
SpreadProperty: types.SpreadProperty;
82-
DoExpression: types.DoExpression;
9+
File: t.File;
10+
Program: t.Program;
11+
Identifier: t.Identifier;
12+
NullLiteral: t.NullLiteral;
13+
StringLiteral: t.StringLiteral;
14+
NumericLiteral: t.NumericLiteral;
15+
BooleanLiteral: t.BooleanLiteral;
16+
RegExpLiteral: t.RegExpLiteral;
17+
FunctionDeclaration: t.FunctionDeclaration;
18+
FunctionExpression: t.FunctionExpression;
19+
ArrowFunctionExpression: t.ArrowFunctionExpression;
20+
SwitchCase: t.SwitchCase;
21+
CatchClause: t.CatchClause;
22+
VariableDeclarator: t.VariableDeclarator;
23+
ExpressionStatement: t.ExpressionStatement;
24+
BlockStatement: t.BlockStatement;
25+
EmptyStatement: t.EmptyStatement;
26+
DebuggerStatement: t.DebuggerStatement;
27+
WithStatement: t.WithStatement;
28+
ReturnStatement: t.ReturnStatement;
29+
LabeledStatement: t.LabeledStatement;
30+
BreakStatement: t.BreakStatement;
31+
ContinueStatement: t.ContinueStatement;
32+
IfStatement: t.IfStatement;
33+
SwitchStatement: t.SwitchStatement;
34+
ThrowStatement: t.ThrowStatement;
35+
TryStatement: t.TryStatement;
36+
WhileStatement: t.WhileStatement;
37+
DoWhileStatement: t.DoWhileStatement;
38+
ForStatement: t.ForStatement;
39+
ForInStatement: t.ForInStatement;
40+
ForOfStatement: t.ForOfStatement;
41+
VariableDeclaration: t.VariableDeclaration;
42+
ClassDeclaration: t.ClassDeclaration;
43+
ThisExpression: t.ThisExpression;
44+
ArrayExpression: t.ArrayExpression;
45+
ObjectExpression: t.ObjectExpression;
46+
ObjectProperty: t.ObjectProperty;
47+
ObjectMethod: t.ObjectMethod;
48+
YieldExpression: t.YieldExpression;
49+
UnaryExpression: t.UnaryExpression;
50+
UpdateExpression: t.UpdateExpression;
51+
BinaryExpression: t.BinaryExpression;
52+
AssignmentExpression: t.AssignmentExpression;
53+
LogicalExpression: t.LogicalExpression;
54+
MemberExpression: t.MemberExpression;
55+
ConditionalExpression: t.ConditionalExpression;
56+
CallExpression: t.CallExpression;
57+
NewExpression: t.NewExpression;
58+
SequenceExpression: t.SequenceExpression;
59+
TemplateLiteral: t.TemplateLiteral;
60+
TaggedTemplateExpression: t.TaggedTemplateExpression;
61+
ClassExpression: t.ClassExpression;
62+
ClassMethod: t.ClassMethod;
63+
MetaProperty: t.MetaProperty;
64+
AwaitExpression: t.AwaitExpression;
65+
Super: t.Super;
66+
TemplateElement: t.TemplateElement;
67+
SpreadElement: t.SpreadElement;
68+
// ObjectPattern: t.ObjectPattern;
69+
// ArrayPattern: t.ArrayPattern;
70+
RestElement: t.RestElement;
71+
AssignmentPattern: t.AssignmentPattern;
72+
ClassBody: t.ClassBody;
73+
ImportDeclaration: t.ImportDeclaration;
74+
ExportNamedDeclaration: t.ExportNamedDeclaration;
75+
ExportDefaultDeclaration: t.ExportDefaultDeclaration;
76+
// ExportAllDeclaration: t.ExportAllDeclaration;
77+
ImportSpecifier: t.ImportSpecifier;
78+
ImportDefaultSpecifier: t.ImportDefaultSpecifier;
79+
// ImportNamespaceSpecifier: t.ImportNamespaceSpecifier;
80+
ExportSpecifier: t.ExportSpecifier;
81+
SpreadProperty: t.SpreadProperty;
82+
DoExpression: t.DoExpression;
8383
}
8484

8585
export type EvaluateMap = {
8686
[key in keyof INodeTypeMap]: (path: Path<INodeTypeMap[key]>) => any
8787
};
8888

89-
export type EvaluateFunc = (path: Path<types.Node>) => any;
89+
export type EvaluateFunc = (path: Path<t.Node>) => any;

test/ecma5/for/scope.test.ts

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,24 @@ module.exports = {a: a};
9191
}, ErrDuplicateDeclard("a").message);
9292
});
9393

94-
// FIXME: it should throw an error
95-
// test("var in for block and parent scope const some name var", t => {
96-
// const sandbox: any = vm.createContext({});
97-
98-
// t.throws(function() {
99-
// vm.runInContext(
100-
// `
101-
// let a = 1; // define let var
102-
103-
// const arr = [1, 2, 3];
104-
105-
// for (let i = 0; i < arr.length; i++) {
106-
// let a = i;
107-
// let a = 0; // it should throw an error
108-
// }
109-
110-
// module.exports = {a: a};
111-
// `,
112-
// sandbox
113-
// );
114-
// }, new ErrDuplicateDeclard("a").message);
115-
// });
94+
test("var in for block and parent scope const some name var", t => {
95+
const sandbox: any = vm.createContext({});
96+
97+
t.throws(function() {
98+
vm.runInContext(
99+
`
100+
let a = 1; // define let var
101+
102+
const arr = [1, 2, 3];
103+
104+
for (let i = 0; i < arr.length; i++) {
105+
let a = i;
106+
let a = 0; // it should throw an error
107+
}
108+
109+
module.exports = {a: a};
110+
`,
111+
sandbox
112+
);
113+
}, ErrDuplicateDeclard("a").message);
114+
});

0 commit comments

Comments
 (0)