From 08f0672b03ac99c37976dd391ecd98f2a095779c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 18 Nov 2014 17:42:32 -0800 Subject: [PATCH] Move parameter grammar checks to the grammar pass. --- src/compiler/parser.ts | 183 ++++++++++++++---- .../reference/amdModuleName2.errors.txt | 30 +-- .../fatarrowfunctionsOptionalArgs.errors.txt | 23 +-- ...rowfunctionsOptionalArgsErrors1.errors.txt | 8 +- .../reference/parserRealSource11.errors.txt | 5 +- .../reference/parserharness.errors.txt | 5 +- .../fatarrowfunctionsOptionalArgsErrors1.ts | 1 - 7 files changed, 161 insertions(+), 94 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c28cc3818d..1c598e5baa 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1676,7 +1676,6 @@ module ts { } var typeParameters = parseTypeParameters(); var parameters = parseParameterList(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken); - checkParameterList(parameters); var type: TypeNode; @@ -1702,45 +1701,6 @@ module ts { return parseBracketedList(ParsingContext.Parameters, parseParameter, startDelimiter, endDelimiter); } - function checkParameterList(parameters: NodeArray): void { - var seenOptionalParameter = false; - var parameterCount = parameters.length; - - for (var i = 0; i < parameterCount; i++) { - var parameter = parameters[i]; - if (parameter.flags & NodeFlags.Rest) { - if (i !== (parameterCount - 1)) { - grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); - return; - } - - if (parameter.flags & NodeFlags.QuestionMark) { - grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_be_optional); - return; - } - - if (parameter.initializer) { - grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); - return; - } - } - else if (parameter.flags & NodeFlags.QuestionMark || parameter.initializer) { - seenOptionalParameter = true; - - if (parameter.flags & NodeFlags.QuestionMark && parameter.initializer) { - grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); - return; - } - } - else { - if (seenOptionalParameter) { - grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); - return; - } - } - } - } - function parseSignatureMember(kind: SyntaxKind, returnToken: SyntaxKind): SignatureDeclaration { var node = createNode(kind); var sig = parseSignature(kind, returnToken, /* returnTokenRequired */ false); @@ -4372,9 +4332,21 @@ module ts { // No grammar errors on any of our children. Check this node for grammar errors. switch (node.kind) { - case SyntaxKind.Parameter: - return performParameterChecks(node); + case SyntaxKind.ArrowFunction: return performArrowFunctionChecks(node); + case SyntaxKind.CallSignature: return performCallSignatureChecks(node); + case SyntaxKind.Constructor: return performConstructorChecks(node); + case SyntaxKind.ConstructorType: return performConstructorTypeChecks(node); + case SyntaxKind.ConstructSignature: return performConstructSignatureChecks(node); + case SyntaxKind.FunctionDeclaration: return performFunctionDeclarationChecks(node); + case SyntaxKind.FunctionExpression: return performFunctionExpressionChecks(node); + case SyntaxKind.FunctionType: return performFunctionTypeChecks(node); + case SyntaxKind.GetAccessor: return performGetAccessorChecks(node); + case SyntaxKind.Method: return performMethodChecks(node); + case SyntaxKind.Parameter: return performParameterChecks(node); + case SyntaxKind.SetAccessor: return performSetAccessorChecks(node); } + + return false; } function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { @@ -4391,6 +4363,86 @@ module ts { grammarErrorOnNode(node, Diagnostics.Invalid_use_of_0_in_strict_mode, name); } + function performArrowFunctionChecks(node: FunctionExpression) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performCallSignatureChecks(node: ConstructorDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performConstructorChecks(node: ConstructorDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performConstructorTypeChecks(node: SignatureDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performConstructSignatureChecks(node: FunctionLikeDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performFunctionDeclarationChecks(node: FunctionLikeDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performFunctionExpressionChecks(node: FunctionExpression) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performFunctionTypeChecks(node: SignatureDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performGetAccessorChecks(node: MethodDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + + function performMethodChecks(node: MethodDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } + 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 @@ -4404,6 +4456,53 @@ module ts { return false; } + + function performParameterListChecks(parameters: NodeArray): void { + var seenOptionalParameter = false; + var parameterCount = parameters.length; + + for (var i = 0; i < parameterCount; i++) { + var parameter = parameters[i]; + if (parameter.flags & NodeFlags.Rest) { + if (i !== (parameterCount - 1)) { + grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + return; + } + + if (parameter.flags & NodeFlags.QuestionMark) { + grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_be_optional); + return; + } + + if (parameter.initializer) { + grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); + return; + } + } + else if (parameter.flags & NodeFlags.QuestionMark || parameter.initializer) { + seenOptionalParameter = true; + + if (parameter.flags & NodeFlags.QuestionMark && parameter.initializer) { + grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + return; + } + } + else { + if (seenOptionalParameter) { + grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + return; + } + } + } + } + + function performSetAccessorChecks(node: MethodDeclaration) { + if (performParameterListChecks(node.parameters)) { + return true; + } + + return false; + } } diff --git a/tests/baselines/reference/amdModuleName2.errors.txt b/tests/baselines/reference/amdModuleName2.errors.txt index 911f31a1f4..cf7fb82ae1 100644 --- a/tests/baselines/reference/amdModuleName2.errors.txt +++ b/tests/baselines/reference/amdModuleName2.errors.txt @@ -1,16 +1,16 @@ -tests/cases/compiler/amdModuleName2.ts(2,1): error TS2458: An AMD module cannot have multiple name assignments. - - -==== tests/cases/compiler/amdModuleName2.ts (1 errors) ==== - /// - /// - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2458: An AMD module cannot have multiple name assignments. - class Foo { - x: number; - constructor() { - this.x = 5; - } - } - export = Foo; +tests/cases/compiler/amdModuleName2.ts(2,1): error TS2458: An AMD module cannot have multiple name assignments. + + +==== tests/cases/compiler/amdModuleName2.ts (1 errors) ==== + /// + /// + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2458: An AMD module cannot have multiple name assignments. + class Foo { + x: number; + constructor() { + this.x = 5; + } + } + export = Foo; \ No newline at end of file diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgs.errors.txt b/tests/baselines/reference/fatarrowfunctionsOptionalArgs.errors.txt index e445a1460f..db0721c62a 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgs.errors.txt +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgs.errors.txt @@ -1,15 +1,8 @@ -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(60,10): error TS1015: Parameter cannot have question mark and initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(70,11): error TS1015: Parameter cannot have question mark and initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(80,17): error TS1015: Parameter cannot have question mark and initializer. tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(88,23): error TS1005: ';' expected. tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(88,38): error TS1005: ';' expected. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(106,3): error TS1015: Parameter cannot have question mark and initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(106,35): error TS1015: Parameter cannot have question mark and initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(126,6): error TS1015: Parameter cannot have question mark and initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Parameter cannot have question mark and initializer. -==== tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts (9 errors) ==== +==== tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts (2 errors) ==== // valid // no params @@ -70,8 +63,6 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Para false ? (arg: number) => 45 : null; false ? (arg?: number) => 46 : null; false ? (arg?: number = 0) => 47 : null; - ~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. false ? (...arg: number[]) => 48 : null; // in ternary exression within paren @@ -82,8 +73,6 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Para false ? ((arg: number) => 55) : null; false ? ((arg?: number) => 56) : null; false ? ((arg?: number = 0) => 57) : null; - ~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. false ? ((...arg: number[]) => 58) : null; // ternary exression's else clause @@ -94,8 +83,6 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Para false ? null : (arg: number) => 65; false ? null : (arg?: number) => 66; false ? null : (arg?: number = 0) => 67; - ~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. false ? null : (...arg: number[]) => 68; @@ -126,10 +113,6 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Para ((arg:number) => 0) + '' + ((arg:number) => 104); ((arg:number = 1) => 0) + '' + ((arg:number = 2) => 105); ((arg?:number = 1) => 0) + '' + ((arg?:number = 2) => 106); - ~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. - ~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. ((...arg:number[]) => 0) + '' + ((...arg:number[]) => 107); ((arg1, arg2?) => 0) + '' + ((arg1,arg2?) => 108); ((arg1, ...arg2:number[]) => 0) + '' + ((arg1, ...arg2:number[]) => 108); @@ -150,12 +133,8 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgs.ts(128,9): error TS1015: Para (a: number = 0) => 116, (a = 0) => 117, (a?: number = 0) => 118, - ~ -!!! error TS1015: Parameter cannot have question mark and initializer. (...a: number[]) => 119, (a, b? = 0, ...c: number[]) => 120, - ~ -!!! error TS1015: Parameter cannot have question mark and initializer. (a) => (b) => (c) => 121, false? (a) => 0 : (b) => 122 ); \ No newline at end of file diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors1.errors.txt b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors1.errors.txt index ce937dd55d..309e731e54 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors1.errors.txt +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors1.errors.txt @@ -1,11 +1,10 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(1,9): error TS1016: A required parameter cannot follow an optional parameter. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(2,5): error TS1047: A rest parameter cannot be optional. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(4,5): error TS1048: A rest parameter cannot have an initializer. -tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(5,5): error TS1003: Identifier expected. -tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(8,12): error TS1016: A required parameter cannot follow an optional parameter. +tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(7,12): error TS1016: A required parameter cannot follow an optional parameter. -==== tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts (5 errors) ==== +==== tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts (4 errors) ==== (arg1?, arg2) => 101; ~~~~ !!! error TS1016: A required parameter cannot follow an optional parameter. @@ -16,9 +15,6 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts(8,12): error TS1016 (...arg:number [] = []) => 104; ~~~ !!! error TS1048: A rest parameter cannot have an initializer. - (...) => 105; - ~ -!!! error TS1003: Identifier expected. // Non optional parameter following an optional one (arg1 = 1, arg2) => 1; diff --git a/tests/baselines/reference/parserRealSource11.errors.txt b/tests/baselines/reference/parserRealSource11.errors.txt index 966da98009..68fe64a63f 100644 --- a/tests/baselines/reference/parserRealSource11.errors.txt +++ b/tests/baselines/reference/parserRealSource11.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(4,1): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/typescript.ts' not found. tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(193,40): error TS1150: 'new T[]' cannot be used to create an array. Use 'new Array()' instead. -tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(867,29): error TS1015: Parameter cannot have question mark and initializer. tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(1009,45): error TS1150: 'new T[]' cannot be used to create an array. Use 'new Array()' instead. tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(1024,47): error TS1150: 'new T[]' cannot be used to create an array. Use 'new Array()' instead. tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(13,22): error TS2304: Cannot find name 'Type'. @@ -515,7 +514,7 @@ tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(2356,30): error tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(2356,48): error TS2304: Cannot find name 'TokenID'. -==== tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts (515 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts (514 errors) ==== // Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. // See LICENSE.txt in the project root for complete license information. @@ -1815,8 +1814,6 @@ tests/cases/conformance/parser/ecmascript5/parserRealSource11.ts(2356,48): error } public getAliasName(aliasAST?: AST = this.alias) : string { - ~~~~~~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. if (aliasAST.nodeType == NodeType.Name) { ~~~~~~~~ !!! error TS2304: Cannot find name 'NodeType'. diff --git a/tests/baselines/reference/parserharness.errors.txt b/tests/baselines/reference/parserharness.errors.txt index 01104e61ea..4de6566054 100644 --- a/tests/baselines/reference/parserharness.errors.txt +++ b/tests/baselines/reference/parserharness.errors.txt @@ -3,7 +3,6 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(17,1): err tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(18,1): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/services/typescriptServices.ts' not found. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(19,1): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/RealWorld/diff.ts' not found. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(1430,9): error TS1128: Declaration or statement expected. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2047,13): error TS1015: Parameter cannot have question mark and initializer. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(21,21): error TS2305: Module 'Harness' has no exported member 'Assert'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(25,17): error TS2304: Cannot find name 'IIO'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(41,12): error TS2304: Cannot find name 'ActiveXObject'. @@ -111,7 +110,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(1787,68): tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): error TS2304: Cannot find name 'Diff'. -==== tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts (111 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts (110 errors) ==== // // Copyright (c) Microsoft Corporation. All rights reserved. // @@ -2379,8 +2378,6 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): relativeFilename: string, generateContent: () => string, runImmediately? = false, - ~~~~~~~~~~~~~~ -!!! error TS1015: Parameter cannot have question mark and initializer. opts?: BaselineOptions) { var actual = undefined; diff --git a/tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts b/tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts index c684aeca5b..d8ddcf4bb8 100644 --- a/tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts +++ b/tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors1.ts @@ -2,7 +2,6 @@ (...arg?) => 102; (...arg) => 103; (...arg:number [] = []) => 104; -(...) => 105; // Non optional parameter following an optional one (arg1 = 1, arg2) => 1; \ No newline at end of file