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

Commit

Permalink
fix: fix for loop scope with fork a new scope to resolve it
Browse files Browse the repository at this point in the history
  • Loading branch information
axetroy committed Mar 25, 2018
1 parent 294a645 commit ef201f7
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 106 deletions.
17 changes: 10 additions & 7 deletions src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,21 +314,24 @@ const visitors: EvaluateMap = {
const { node, scope } = path;

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

newScope.invasive = true;
newScope.redeclare = true;
forScope.invasive = true; // 有块级作用域

if (node.init) {
evaluate(path.createChild(node.init, newScope));
evaluate(path.createChild(node.init, forScope));
}

for (;;) {
if (node.test && !evaluate(path.createChild(node.test, newScope))) {
// every loop will create it's own scope
// it should inherit from forScope
const loopScope = forScope.fork();

if (node.test && !evaluate(path.createChild(node.test, forScope))) {
break;
}

const result = evaluate(path.createChild(node.body, newScope));
const result = evaluate(path.createChild(node.body, loopScope));
if (Signal.isBreak(result)) {
break;
} else if (Signal.isContinue(result)) {
Expand All @@ -337,7 +340,7 @@ const visitors: EvaluateMap = {
return result;
}
if (node.update) {
evaluate(path.createChild(node.update, newScope));
evaluate(path.createChild(node.update, forScope));
}
}
},
Expand Down
22 changes: 21 additions & 1 deletion src/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class Scope {
}
}

public all(): { [key: string]: any } {
public raw(): { [key: string]: any } {
const map = {};
for (const varName in this.content) {
if (this.content.hasOwnProperty(varName)) {
Expand Down Expand Up @@ -141,4 +141,24 @@ export class Scope {
public createChild(type: ScopeType, label?: string): Scope {
return new Scope(type, this, label);
}
public fork(): Scope {
// forks a new scope
const newScope = new Scope("block", null);

// copy the properties
newScope.invasive = this.invasive;
newScope.redeclare = this.redeclare;
newScope.isTopLevel = this.isTopLevel;
newScope.context = this.context;
newScope.parent = this.parent;

// copy the vars
for (const varName in this.content) {
if (this.content.hasOwnProperty(varName)) {
const $var = this.content[varName];
newScope.declare($var.kind, $var.name, $var.value);
}
}
return newScope;
}
}
152 changes: 76 additions & 76 deletions src/type.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,89 @@
import * as types from "babel-types";
import * as t from "babel-types";
import { Path } from "./path";

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

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

export interface INodeTypeMap {
File: types.File;
Program: types.Program;
Identifier: types.Identifier;
NullLiteral: types.NullLiteral;
StringLiteral: types.StringLiteral;
NumericLiteral: types.NumericLiteral;
BooleanLiteral: types.BooleanLiteral;
RegExpLiteral: types.RegExpLiteral;
FunctionDeclaration: types.FunctionDeclaration;
FunctionExpression: types.FunctionExpression;
ArrowFunctionExpression: types.ArrowFunctionExpression;
SwitchCase: types.SwitchCase;
CatchClause: types.CatchClause;
VariableDeclarator: types.VariableDeclarator;
ExpressionStatement: types.ExpressionStatement;
BlockStatement: types.BlockStatement;
EmptyStatement: types.EmptyStatement;
DebuggerStatement: types.DebuggerStatement;
WithStatement: types.WithStatement;
ReturnStatement: types.ReturnStatement;
LabeledStatement: types.LabeledStatement;
BreakStatement: types.BreakStatement;
ContinueStatement: types.ContinueStatement;
IfStatement: types.IfStatement;
SwitchStatement: types.SwitchStatement;
ThrowStatement: types.ThrowStatement;
TryStatement: types.TryStatement;
WhileStatement: types.WhileStatement;
DoWhileStatement: types.DoWhileStatement;
ForStatement: types.ForStatement;
ForInStatement: types.ForInStatement;
ForOfStatement: types.ForOfStatement;
VariableDeclaration: types.VariableDeclaration;
ClassDeclaration: types.ClassDeclaration;
ThisExpression: types.ThisExpression;
ArrayExpression: types.ArrayExpression;
ObjectExpression: types.ObjectExpression;
ObjectProperty: types.ObjectProperty;
ObjectMethod: types.ObjectMethod;
YieldExpression: types.YieldExpression;
UnaryExpression: types.UnaryExpression;
UpdateExpression: types.UpdateExpression;
BinaryExpression: types.BinaryExpression;
AssignmentExpression: types.AssignmentExpression;
LogicalExpression: types.LogicalExpression;
MemberExpression: types.MemberExpression;
ConditionalExpression: types.ConditionalExpression;
CallExpression: types.CallExpression;
NewExpression: types.NewExpression;
SequenceExpression: types.SequenceExpression;
TemplateLiteral: types.TemplateLiteral;
TaggedTemplateExpression: types.TaggedTemplateExpression;
ClassExpression: types.ClassExpression;
ClassMethod: types.ClassMethod;
MetaProperty: types.MetaProperty;
AwaitExpression: types.AwaitExpression;
Super: types.Super;
TemplateElement: types.TemplateElement;
SpreadElement: types.SpreadElement;
// ObjectPattern: types.ObjectPattern;
// ArrayPattern: types.ArrayPattern;
RestElement: types.RestElement;
AssignmentPattern: types.AssignmentPattern;
ClassBody: types.ClassBody;
ImportDeclaration: types.ImportDeclaration;
ExportNamedDeclaration: types.ExportNamedDeclaration;
ExportDefaultDeclaration: types.ExportDefaultDeclaration;
// ExportAllDeclaration: types.ExportAllDeclaration;
ImportSpecifier: types.ImportSpecifier;
ImportDefaultSpecifier: types.ImportDefaultSpecifier;
// ImportNamespaceSpecifier: types.ImportNamespaceSpecifier;
ExportSpecifier: types.ExportSpecifier;
SpreadProperty: types.SpreadProperty;
DoExpression: types.DoExpression;
File: t.File;
Program: t.Program;
Identifier: t.Identifier;
NullLiteral: t.NullLiteral;
StringLiteral: t.StringLiteral;
NumericLiteral: t.NumericLiteral;
BooleanLiteral: t.BooleanLiteral;
RegExpLiteral: t.RegExpLiteral;
FunctionDeclaration: t.FunctionDeclaration;
FunctionExpression: t.FunctionExpression;
ArrowFunctionExpression: t.ArrowFunctionExpression;
SwitchCase: t.SwitchCase;
CatchClause: t.CatchClause;
VariableDeclarator: t.VariableDeclarator;
ExpressionStatement: t.ExpressionStatement;
BlockStatement: t.BlockStatement;
EmptyStatement: t.EmptyStatement;
DebuggerStatement: t.DebuggerStatement;
WithStatement: t.WithStatement;
ReturnStatement: t.ReturnStatement;
LabeledStatement: t.LabeledStatement;
BreakStatement: t.BreakStatement;
ContinueStatement: t.ContinueStatement;
IfStatement: t.IfStatement;
SwitchStatement: t.SwitchStatement;
ThrowStatement: t.ThrowStatement;
TryStatement: t.TryStatement;
WhileStatement: t.WhileStatement;
DoWhileStatement: t.DoWhileStatement;
ForStatement: t.ForStatement;
ForInStatement: t.ForInStatement;
ForOfStatement: t.ForOfStatement;
VariableDeclaration: t.VariableDeclaration;
ClassDeclaration: t.ClassDeclaration;
ThisExpression: t.ThisExpression;
ArrayExpression: t.ArrayExpression;
ObjectExpression: t.ObjectExpression;
ObjectProperty: t.ObjectProperty;
ObjectMethod: t.ObjectMethod;
YieldExpression: t.YieldExpression;
UnaryExpression: t.UnaryExpression;
UpdateExpression: t.UpdateExpression;
BinaryExpression: t.BinaryExpression;
AssignmentExpression: t.AssignmentExpression;
LogicalExpression: t.LogicalExpression;
MemberExpression: t.MemberExpression;
ConditionalExpression: t.ConditionalExpression;
CallExpression: t.CallExpression;
NewExpression: t.NewExpression;
SequenceExpression: t.SequenceExpression;
TemplateLiteral: t.TemplateLiteral;
TaggedTemplateExpression: t.TaggedTemplateExpression;
ClassExpression: t.ClassExpression;
ClassMethod: t.ClassMethod;
MetaProperty: t.MetaProperty;
AwaitExpression: t.AwaitExpression;
Super: t.Super;
TemplateElement: t.TemplateElement;
SpreadElement: t.SpreadElement;
// ObjectPattern: t.ObjectPattern;
// ArrayPattern: t.ArrayPattern;
RestElement: t.RestElement;
AssignmentPattern: t.AssignmentPattern;
ClassBody: t.ClassBody;
ImportDeclaration: t.ImportDeclaration;
ExportNamedDeclaration: t.ExportNamedDeclaration;
ExportDefaultDeclaration: t.ExportDefaultDeclaration;
// ExportAllDeclaration: t.ExportAllDeclaration;
ImportSpecifier: t.ImportSpecifier;
ImportDefaultSpecifier: t.ImportDefaultSpecifier;
// ImportNamespaceSpecifier: t.ImportNamespaceSpecifier;
ExportSpecifier: t.ExportSpecifier;
SpreadProperty: t.SpreadProperty;
DoExpression: t.DoExpression;
}

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

export type EvaluateFunc = (path: Path<types.Node>) => any;
export type EvaluateFunc = (path: Path<t.Node>) => any;
43 changes: 21 additions & 22 deletions test/ecma5/for/scope.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,25 +91,24 @@ module.exports = {a: a};
}, ErrDuplicateDeclard("a").message);
});

// FIXME: it should throw an error
// test("var in for block and parent scope const some name var", t => {
// const sandbox: any = vm.createContext({});

// t.throws(function() {
// vm.runInContext(
// `
// let a = 1; // define let var

// const arr = [1, 2, 3];

// for (let i = 0; i < arr.length; i++) {
// let a = i;
// let a = 0; // it should throw an error
// }

// module.exports = {a: a};
// `,
// sandbox
// );
// }, new ErrDuplicateDeclard("a").message);
// });
test("var in for block and parent scope const some name var", t => {
const sandbox: any = vm.createContext({});

t.throws(function() {
vm.runInContext(
`
let a = 1; // define let var
const arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {
let a = i;
let a = 0; // it should throw an error
}
module.exports = {a: a};
`,
sandbox
);
}, ErrDuplicateDeclard("a").message);
});

0 comments on commit ef201f7

Please sign in to comment.