From 6fdc5dc14840e885a659239c92bcf2c9cbd7a899 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 18 Nov 2014 17:01:39 -0800 Subject: [PATCH] Move parameter name 'strict' checking to the grammar walker. --- src/compiler/parser.ts | 65 +++++++++++++++---- src/compiler/types.ts | 30 +++++---- .../StrictMode/parserStrictMode12.ts | 1 + 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2f51cd294e7..c28cc3818de 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1169,6 +1169,11 @@ module ts { function finishNode(node: T): T { node.end = scanner.getStartPos(); + + if (isInStrictMode) { + node.flags |= NodeFlags.ParsedInStrictMode; + } + return node; } @@ -1703,16 +1708,7 @@ module ts { for (var i = 0; i < parameterCount; i++) { var parameter = parameters[i]; - // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the - // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code - // or if its FunctionBody is strict code(11.1.5). - // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a - // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) - if (isInStrictMode && isEvalOrArgumentsIdentifier(parameter.name)) { - reportInvalidUseInStrictMode(parameter.name); - return; - } - else if (parameter.flags & NodeFlags.Rest) { + if (parameter.flags & NodeFlags.Rest) { if (i !== (parameterCount - 1)) { grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); return; @@ -4322,7 +4318,7 @@ module ts { else { // No parser errors were reported. Perform our stricted grammar checks. file._syntacticDiagnostics = []; - performGrammarChecks(file); + performGrammarChecks(sourceText, file); } file._parserDiagnostics = undefined; @@ -4363,9 +4359,54 @@ module ts { return file; } - function performGrammarChecks(child: Node) { + function performGrammarChecks(sourceText: string, file: SourceFileInternal) { + performNodeChecks(file); + + function performNodeChecks(node: Node) { + // First recurse and perform all grammar checks on the children of this node. If any + // children had an grammar error, then skip reporting errors for this node or anything + // higher. + if (forEachChild(node, performNodeChecks)) { + return true; + } + + // No grammar errors on any of our children. Check this node for grammar errors. + switch (node.kind) { + case SyntaxKind.Parameter: + return performParameterChecks(node); + } + } + + function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { + var span = getErrorSpanForNode(node); + var start = span.end > span.pos ? skipTrivia(file.text, span.pos) : span.pos; + var length = span.end - start; + + file._syntacticDiagnostics.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); + } + + function reportInvalidUseInStrictMode(node: Identifier): void { + // declarationNameToString cannot be used here since it uses a backreference to 'parent' that is not yet set + var name = sourceText.substring(skipTrivia(sourceText, node.pos), node.end); + grammarErrorOnNode(node, Diagnostics.Invalid_use_of_0_in_strict_mode, name); + } + + function performParameterChecks(node: ParameterDeclaration): boolean { + // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the + // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code + // or if its FunctionBody is strict code(11.1.5). + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a + // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) + if (node.flags & NodeFlags.ParsedInStrictMode && isEvalOrArgumentsIdentifier(node.name)) { + reportInvalidUseInStrictMode(node.name); + return true; + } + + return false; + } } + export function createProgram(rootNames: string[], options: CompilerOptions, host: CompilerHost): Program { var program: Program; var files: SourceFile[] = []; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1ffbf12284c..227034993ca 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -256,19 +256,23 @@ module ts { } export const enum NodeFlags { - Export = 0x00000001, // Declarations - Ambient = 0x00000002, // Declarations - QuestionMark = 0x00000004, // Parameter/Property/Method - Rest = 0x00000008, // Parameter - Public = 0x00000010, // Property/Method - Private = 0x00000020, // Property/Method - Protected = 0x00000040, // Property/Method - Static = 0x00000080, // Property/Method - MultiLine = 0x00000100, // Multi-line array or object literal - Synthetic = 0x00000200, // Synthetic node (for full fidelity) - DeclarationFile = 0x00000400, // Node is a .d.ts file - Let = 0x00000800, // Variable declaration - Const = 0x00001000, // Variable declaration + Export = 0x00000001, // Declarations + Ambient = 0x00000002, // Declarations + QuestionMark = 0x00000004, // Parameter/Property/Method + Rest = 0x00000008, // Parameter + Public = 0x00000010, // Property/Method + Private = 0x00000020, // Property/Method + Protected = 0x00000040, // Property/Method + Static = 0x00000080, // Property/Method + MultiLine = 0x00000100, // Multi-line array or object literal + Synthetic = 0x00000200, // Synthetic node (for full fidelity) + DeclarationFile = 0x00000400, // Node is a .d.ts file + Let = 0x00000800, // Variable declaration + Const = 0x00001000, // Variable declaration + + // Set if this node was parsed in strict mode. Used for grammar error checks, as well as + // checking if the node can be reused in incremental settings. + ParsedInStrictMode = 0x00002000, Modifier = Export | Ambient | Public | Private | Protected | Static, AccessibilityModifier = Public | Private | Protected, diff --git a/tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts b/tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts index 5d89dfc3b71..e8374347196 100644 --- a/tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts +++ b/tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts @@ -1,2 +1,3 @@ +// @target: ES5 "use strict"; var v = { set foo(eval) { } } \ No newline at end of file