Skip to content

Commit

Permalink
Handle ForStatement and ForInStatement with lexical declaration.
Browse files Browse the repository at this point in the history
Also, to make it explicit, constructing a lexical declaration (const or
let) is separated from the common variable declaration (var).

Refs jquery#1065
  • Loading branch information
ariya committed Feb 22, 2015
1 parent ef882ce commit dae6e7d
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 29 deletions.
107 changes: 80 additions & 27 deletions esprima.js
Expand Up @@ -1951,7 +1951,15 @@
return this;
},

finishVariableDeclaration: function (declarations, kind) {
finishVariableDeclaration: function (declarations) {
this.type = Syntax.VariableDeclaration;
this.declarations = declarations;
this.kind = 'var';
this.finish();
return this;
},

finishLexicalDeclaration: function (declarations, kind) {
this.type = Syntax.VariableDeclaration;
this.declarations = declarations;
this.kind = kind;
Expand Down Expand Up @@ -3032,7 +3040,7 @@
return node.finishIdentifier(token.value);
}

function parseVariableDeclaration(kind) {
function parseVariableDeclaration() {
var init = null, id, node = new Node();

id = parseVariableIdentifier();
Expand All @@ -3042,22 +3050,19 @@
tolerateError(Messages.StrictVarName);
}

if (kind === 'const') {
expect('=');
init = parseAssignmentExpression();
} else if (match('=')) {
if (match('=')) {
lex();
init = parseAssignmentExpression();
}

return node.finishVariableDeclarator(id, init);
}

function parseVariableDeclarationList(kind) {
function parseVariableDeclarationList() {
var list = [];

do {
list.push(parseVariableDeclaration(kind));
list.push(parseVariableDeclaration());
if (!match(',')) {
break;
}
Expand All @@ -3076,7 +3081,42 @@

consumeSemicolon();

return node.finishVariableDeclaration(declarations, 'var');
return node.finishVariableDeclaration(declarations);
}

function parseLexicalBinding(kind) {
var init = null, id, node = new Node();

id = parseVariableIdentifier();

// 12.2.1
if (strict && isRestrictedWord(id.name)) {
tolerateError(Messages.StrictVarName);
}

if (kind === 'const') {
expect('=');
init = parseAssignmentExpression();
} else if (match('=')) {
lex();
init = parseAssignmentExpression();
}

return node.finishVariableDeclarator(id, init);
}

function parseBindingList(kind) {
var list = [];

do {
list.push(parseLexicalBinding(kind));
if (!match(',')) {
break;
}
lex();
} while (startIndex < length);

return list;
}

function parseLexicalDeclaration() {
Expand All @@ -3085,11 +3125,11 @@
kind = lex().value;
assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');

declarations = parseVariableDeclarationList(kind);
declarations = parseBindingList(kind);

consumeSemicolon();

return node.finishVariableDeclaration(declarations, kind);
return node.finishLexicalDeclaration(declarations, kind);
}

// 12.3 Empty Statement
Expand Down Expand Up @@ -3182,17 +3222,9 @@
return node.finishWhileStatement(test, body);
}

function parseForVariableDeclaration() {
var token, declarations, node = new Node();

token = lex();
declarations = parseVariableDeclarationList();

return node.finishVariableDeclaration(declarations, token.value);
}

function parseForStatement(node) {
var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn;
var init, test, update, left, right, kind, declarations,
body, oldInIteration, previousAllowIn = state.allowIn;

init = test = update = null;

Expand All @@ -3203,16 +3235,39 @@
if (match(';')) {
lex();
} else {
if (matchKeyword('var') || matchKeyword('let')) {
if (matchKeyword('var')) {
init = new Node();
lex();

state.allowIn = false;
init = parseForVariableDeclaration();
init = init.finishVariableDeclaration(parseVariableDeclarationList());
state.allowIn = previousAllowIn;

if (init.declarations.length === 1 && matchKeyword('in')) {
lex();
left = init;
right = parseExpression();
init = null;
} else {
expect(';');
}
} else if (matchKeyword('const') || matchKeyword('let')) {
init = new Node();
kind = lex().value;

state.allowIn = false;
declarations = parseBindingList(kind);
state.allowIn = previousAllowIn;

if (declarations.length === 1 && matchKeyword('in')) {
init = init.finishLexicalDeclaration(declarations, kind);
lex();
left = init;
right = parseExpression();
init = null;
} else {
consumeSemicolon();
init = init.finishLexicalDeclaration(declarations, kind);
}
} else {
state.allowIn = false;
Expand All @@ -3229,12 +3284,10 @@
left = init;
right = parseExpression();
init = null;
} else {
expect(';');
}
}

if (typeof left === 'undefined') {
expect(';');
}
}

if (typeof left === 'undefined') {
Expand Down
63 changes: 61 additions & 2 deletions test/test.js
Expand Up @@ -20325,10 +20325,10 @@ var testFixture = {
}
}],
kind: 'let',
range: [4, 13],
range: [4, 14],
loc: {
start: { line: 1, column: 4 },
end: { line: 1, column: 13 }
end: { line: 1, column: 14 }
}
},
test: null,
Expand Down Expand Up @@ -31539,6 +31539,65 @@ var testFixture = {
}]
},

'"use strict"; let eval;': {
type: 'Program',
body: [{
type: 'ExpressionStatement',
expression: {
type: 'Literal',
value: 'use strict',
raw: '"use strict"',
range: [0, 12],
loc: {
start: { line: 1, column: 0 },
end: { line: 1, column: 12 }
}
},
range: [0, 13],
loc: {
start: { line: 1, column: 0 },
end: { line: 1, column: 13 }
}
}, {
type: 'VariableDeclaration',
declarations: [{
type: 'VariableDeclarator',
id: {
type: 'Identifier',
name: 'eval',
range: [18, 22],
loc: {
start: { line: 1, column: 18 },
end: { line: 1, column: 22 }
}
},
init: null,
range: [18, 22],
loc: {
start: { line: 1, column: 18 },
end: { line: 1, column: 22 }
}
}],
kind: 'let',
range: [14, 23],
loc: {
start: { line: 1, column: 14 },
end: { line: 1, column: 23 }
}
}],
range: [0, 23],
loc: {
start: { line: 1, column: 0 },
end: { line: 1, column: 23 }
},
errors: [{
index: 22,
lineNumber: 1,
column: 23,
message: 'Error: Line 1: Variable name may not be eval or arguments in strict mode'
}]
},

'"use strict"; var arguments;': {
type: 'Program',
body: [{
Expand Down

0 comments on commit dae6e7d

Please sign in to comment.