Skip to content

Commit 6702223

Browse files
committed
Handle future reserved keywords in parameters
If, after parsing the function body, we changed from non strict to strict mode we go through the parameters to ensure we do not have an future reserved keywords. Part of google#242 Review URL: google#256 Closes google#256.
1 parent 97e0203 commit 6702223

File tree

7 files changed

+307
-195
lines changed

7 files changed

+307
-195
lines changed

bin/traceur.js

Lines changed: 225 additions & 183 deletions
Large diffs are not rendered by default.

src/staticsemantics/StrictParams.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2013 Traceur Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import {ParseTreeVisitor} from '../syntax/ParseTreeVisitor.js';
16+
import {isStrictKeyword} from '../syntax/Keywords.js';
17+
18+
/**
19+
* This matches the "Static Semantics: BoundNames" in the ES6 spec.
20+
*/
21+
export class StrictParams extends ParseTreeVisitor {
22+
23+
/**
24+
* @param {ErrorReporter} errorReporter
25+
*/
26+
constructor(errorReporter) {
27+
super();
28+
this.errorReporter = errorReporter;
29+
}
30+
31+
visitBindingIdentifier(tree) {
32+
var name = tree.identifierToken.value;
33+
if (isStrictKeyword(name)) {
34+
this.errorReporter.reportError(tree.location.start,
35+
`${name} is a reserved identifier`);
36+
}
37+
}
38+
39+
static visit(tree, errorReporter) {
40+
new StrictParams(errorReporter).visitAny(tree);
41+
}
42+
}
43+

src/syntax/Keywords.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,8 @@ strictKeywords.forEach((value) => {
9090

9191
export function getKeywordType(value) {
9292
return keywordsByName[value];
93-
};
93+
}
94+
95+
export function isStrictKeyword(value) {
96+
return getKeywordType(value) === STRICT_KEYWORD;
97+
}

src/syntax/Parser.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
} from './PredefinedName.js';
5151
import {Scanner} from './Scanner.js';
5252
import {SourceRange} from '../util/SourceRange.js';
53+
import {StrictParams} from '../staticsemantics/StrictParams.js';
5354
import {
5455
Token,
5556
isAssignmentOperator
@@ -514,7 +515,11 @@ export class Parser {
514515
}
515516

516517
peekId_(type) {
517-
return type === IDENTIFIER;
518+
if (type === IDENTIFIER)
519+
return true;
520+
if (this.strictMode_)
521+
return false;
522+
return this.peekToken_().isStrictKeyword();
518523
}
519524

520525
peekIdName_(token) {
@@ -803,7 +808,8 @@ export class Parser {
803808
this.eat_(OPEN_PAREN);
804809
var formalParameterList = this.parseFormalParameterList_();
805810
this.eat_(CLOSE_PAREN);
806-
var functionBody = this.parseFunctionBody_(isGenerator);
811+
var functionBody = this.parseFunctionBody_(isGenerator,
812+
formalParameterList);
807813
return new FunctionDeclaration(this.getTreeLocation_(start), name,
808814
isGenerator, formalParameterList,
809815
functionBody);
@@ -824,7 +830,8 @@ export class Parser {
824830
this.eat_(OPEN_PAREN);
825831
var formalParameterList = this.parseFormalParameterList_();
826832
this.eat_(CLOSE_PAREN);
827-
var functionBody = this.parseFunctionBody_(isGenerator);
833+
var functionBody = this.parseFunctionBody_(isGenerator,
834+
formalParameterList);
828835
return new FunctionExpression(this.getTreeLocation_(start), name,
829836
isGenerator, formalParameterList,
830837
functionBody);
@@ -894,7 +901,7 @@ export class Parser {
894901
* @return {Block}
895902
* @private
896903
*/
897-
parseFunctionBody_(isGenerator) {
904+
parseFunctionBody_(isGenerator, params) {
898905
var start = this.getTreeStartLocation_();
899906
this.eat_(OPEN_CURLY);
900907

@@ -904,6 +911,9 @@ export class Parser {
904911

905912
var result = this.parseStatementList_(!strictMode);
906913

914+
if (!strictMode && this.strictMode_ && params)
915+
StrictParams.visit(params, this.errorReporter_);
916+
907917
this.strictMode_ = strictMode;
908918
this.allowYield_ = allowYield;
909919

@@ -2044,7 +2054,8 @@ export class Parser {
20442054
this.eat_(OPEN_PAREN);
20452055
var formalParameterList = this.parseFormalParameterList_();
20462056
this.eat_(CLOSE_PAREN);
2047-
var functionBody = this.parseFunctionBody_(isGenerator);
2057+
var functionBody = this.parseFunctionBody_(isGenerator,
2058+
formalParameterList);
20482059
return new PropertyMethodAssignment(this.getTreeLocation_(start),
20492060
isStatic, isGenerator, name, formalParameterList, functionBody);
20502061
}
@@ -2072,7 +2083,7 @@ export class Parser {
20722083
var name = this.parsePropertyName_();
20732084
this.eat_(OPEN_PAREN);
20742085
this.eat_(CLOSE_PAREN);
2075-
var body = this.parseFunctionBody_(isGenerator);
2086+
var body = this.parseFunctionBody_(isGenerator, null);
20762087
return new GetAccessor(this.getTreeLocation_(start), isStatic, name, body);
20772088
}
20782089

@@ -2082,7 +2093,7 @@ export class Parser {
20822093
this.eat_(OPEN_PAREN);
20832094
var parameter = this.parsePropertySetParameterList_();
20842095
this.eat_(CLOSE_PAREN);
2085-
var body = this.parseFunctionBody_(isGenerator);
2096+
var body = this.parseFunctionBody_(isGenerator, parameter);
20862097
return new SetAccessor(this.getTreeLocation_(start), isStatic, name,
20872098
parameter, body);
20882099
}

src/util/ErrorReporter.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,16 @@ export class ErrorReporter {
2525
* @param {SourcePosition} location
2626
* @param {string} format
2727
*/
28-
reportError(location, format, var_args) {
28+
reportError(location, format, ...args) {
2929
this.hadError_ = true;
30-
var args = Array.prototype.slice.call(arguments, 2);
3130
this.reportMessageInternal(location, 'error', format, args);
3231
}
3332

3433
/**
3534
* @param {SourcePosition} location
3635
* @param {string} format
3736
*/
38-
reportWarning(location, format, var_args) {
39-
var args = Array.prototype.slice.call(arguments, 2);
37+
reportWarning(location, format, ...args) {
4038
this.reportMessageInternal(location, 'warn', format, args);
4139
}
4240

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Should not compile.
2+
// Error: :4:25: implements is a reserved identifier
3+
4+
function testImplements(implements) {
5+
'use strict';
6+
return 42;
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Should not compile.
2+
// Error: :4:26: implements is a reserved identifier
3+
4+
function testImplements({implements}) {
5+
'use strict';
6+
return 42;
7+
}

0 commit comments

Comments
 (0)