mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 10:41:56 -05:00
Remove 'strict mode' from parsing and checking, and make it purely something purely checked at bind time.
This commit is contained in:
@@ -88,6 +88,8 @@ namespace ts {
|
||||
let container: Node;
|
||||
let blockScopeContainer: Node;
|
||||
let lastContainer: Node;
|
||||
let inStrictMode = false;
|
||||
|
||||
let symbolCount = 0;
|
||||
let Symbol = objectAllocator.getSymbolConstructor();
|
||||
let classifiableNames: Map<string> = {};
|
||||
@@ -531,6 +533,48 @@ namespace ts {
|
||||
typeLiteralSymbol.members = { [symbol.name]: symbol };
|
||||
}
|
||||
|
||||
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
|
||||
if (inStrictMode) {
|
||||
let seen: Map<number> = {};
|
||||
const Property = 1;
|
||||
const NonProperty = 2;
|
||||
|
||||
for (let prop of node.properties) {
|
||||
if (prop.name.kind !== SyntaxKind.Identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let identifier = <Identifier>prop.name;
|
||||
|
||||
// ECMA-262 11.1.5 Object Initialiser
|
||||
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
|
||||
// a.This production is contained in strict code and IsDataDescriptor(previous) is true and
|
||||
// IsDataDescriptor(propId.descriptor) is true.
|
||||
// b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true.
|
||||
// c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true.
|
||||
// d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true
|
||||
// and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields
|
||||
let currentKind = prop.kind === SyntaxKind.PropertyAssignment || prop.kind === SyntaxKind.ShorthandPropertyAssignment || prop.kind === SyntaxKind.MethodDeclaration
|
||||
? Property
|
||||
: NonProperty;
|
||||
|
||||
let existingKind = seen[identifier.text];
|
||||
if (!existingKind) {
|
||||
seen[identifier.text] = currentKind;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentKind === Property && existingKind === Property) {
|
||||
let span = getErrorSpanForNode(file, identifier);
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
|
||||
Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
|
||||
}
|
||||
|
||||
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) {
|
||||
let symbol = createSymbol(symbolFlags, name);
|
||||
addDeclarationToSymbol(symbol, node, symbolFlags);
|
||||
@@ -563,10 +607,11 @@ namespace ts {
|
||||
// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
|
||||
// check for reserved words used as identifiers in strict mode code.
|
||||
function checkStrictModeIdentifier(node: Identifier) {
|
||||
if (node.parserContextFlags & ParserContextFlags.StrictMode &&
|
||||
if (inStrictMode &&
|
||||
node.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord &&
|
||||
node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord &&
|
||||
!isIdentifierName(node)) {
|
||||
|
||||
// Report error only if there are no parse errors in file
|
||||
if (!file.parseDiagnostics.length) {
|
||||
let message = getAncestor(node, SyntaxKind.ClassDeclaration) || getAncestor(node, SyntaxKind.ClassExpression) ?
|
||||
@@ -577,6 +622,96 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeBinaryExpression(node: BinaryExpression) {
|
||||
if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
|
||||
// ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
|
||||
// Assignment operator(11.13) or of a PostfixExpression(11.3)
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.left);
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeCatchClause(node: CatchClause) {
|
||||
// It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the
|
||||
// Catch production is eval or arguments
|
||||
if (inStrictMode && node.variableDeclaration) {
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, node.variableDeclaration.name);
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeDeleteExpression(node: DeleteExpression) {
|
||||
// Grammar checking
|
||||
if (inStrictMode && node.expression.kind === SyntaxKind.Identifier) {
|
||||
// When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
|
||||
// UnaryExpression is a direct reference to a variable, function argument, or function name
|
||||
let span = getErrorSpanForNode(file, node.expression);
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode));
|
||||
}
|
||||
}
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
|
||||
}
|
||||
|
||||
function checkGrammarEvalOrArgumentsInStrictMode(contextNode: Node, name: Node) {
|
||||
if (name && name.kind === SyntaxKind.Identifier) {
|
||||
let identifier = <Identifier>name;
|
||||
if (isEvalOrArgumentsIdentifier(identifier)) {
|
||||
// We check first if the name is inside class declaration or class expression; if so give explicit message
|
||||
// otherwise report generic error message.
|
||||
let span = getErrorSpanForNode(file, name);
|
||||
let message = getAncestor(identifier, SyntaxKind.ClassDeclaration) || getAncestor(identifier, SyntaxKind.ClassExpression) ?
|
||||
Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode :
|
||||
Diagnostics.Invalid_use_of_0_in_strict_mode;
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, identifier.text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeFunctionName(node: FunctionLikeDeclaration) {
|
||||
if (inStrictMode) {
|
||||
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, node.name);
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeNumericLiteral(node: LiteralExpression) {
|
||||
if (inStrictMode && node.flags & NodeFlags.OctalLiteral) {
|
||||
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModePostfixUnaryExpression(node: PostfixUnaryExpression) {
|
||||
// Grammar checking
|
||||
// The identifier eval or arguments may not appear as the LeftHandSideExpression of an
|
||||
// Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression
|
||||
// operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator.
|
||||
if (inStrictMode) {
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModePrefixUnaryExpression(node: PrefixUnaryExpression) {
|
||||
// Grammar checking
|
||||
if (inStrictMode) {
|
||||
if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkStrictModeWithStatement(node: WithStatement) {
|
||||
// Grammar checking for withStatement
|
||||
if (inStrictMode) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
|
||||
}
|
||||
}
|
||||
|
||||
function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
|
||||
let span = getSpanOfTokenAtPosition(file, node.pos);
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
function getDestructuringParameterName(node: Declaration) {
|
||||
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
|
||||
}
|
||||
@@ -584,6 +719,11 @@ namespace ts {
|
||||
function bind(node: Node) {
|
||||
node.parent = parent;
|
||||
|
||||
var savedInStrictMode = inStrictMode;
|
||||
if (!savedInStrictMode) {
|
||||
updateStrictMode(node);
|
||||
}
|
||||
|
||||
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
|
||||
// and then potentially add the symbol to an appropriate symbol table. Possible
|
||||
// destination symbol tables are:
|
||||
@@ -601,19 +741,76 @@ namespace ts {
|
||||
// the current 'container' node when it changes. This helps us know which symbol table
|
||||
// a local should go into for example.
|
||||
bindChildren(node);
|
||||
|
||||
inStrictMode = savedInStrictMode;
|
||||
}
|
||||
|
||||
function updateStrictMode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
updateStrictModeStatementList((<SourceFile>node).statements);
|
||||
return;
|
||||
case SyntaxKind.Block:
|
||||
if (isFunctionLike(node.parent)) {
|
||||
updateStrictModeStatementList((<Block>node).statements);
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
inStrictMode = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function updateStrictModeStatementList(statements: NodeArray<Statement>) {
|
||||
for (let statement of statements) {
|
||||
if (!isPrologueDirective(statement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUseStrictPrologueDirective(statement)) {
|
||||
inStrictMode = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
|
||||
function isUseStrictPrologueDirective(node: Node): boolean {
|
||||
Debug.assert(isPrologueDirective(node));
|
||||
let nodeText = getTextOfNodeFromSourceText(file.text, (<ExpressionStatement>node).expression);
|
||||
|
||||
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
|
||||
// string to contain unicode escapes (as per ES5).
|
||||
return nodeText === '"use strict"' || nodeText === "'use strict'";
|
||||
}
|
||||
|
||||
function bindWorker(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return checkStrictModeIdentifier(<Identifier>node);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return checkStrictModeBinaryExpression(<BinaryExpression>node);
|
||||
case SyntaxKind.CatchClause:
|
||||
return checkStrictModeCatchClause(<CatchClause>node);
|
||||
case SyntaxKind.DeleteExpression:
|
||||
return checkStrictModeDeleteExpression(<DeleteExpression>node);
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return checkStrictModeNumericLiteral(<LiteralExpression>node);
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return checkStrictModePostfixUnaryExpression(<PostfixUnaryExpression>node);
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
|
||||
case SyntaxKind.WithStatement:
|
||||
return checkStrictModeWithStatement(<WithStatement>node);
|
||||
|
||||
case SyntaxKind.TypeParameter:
|
||||
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
case SyntaxKind.Parameter:
|
||||
return bindParameter(<ParameterDeclaration>node);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return bindVariableDeclarationOrBindingElement(<BindingElement | VariableDeclaration>node);
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
|
||||
@@ -635,6 +832,7 @@ namespace ts {
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Method | ((<MethodDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None),
|
||||
isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
checkStrictModeFunctionName(<FunctionDeclaration>node);
|
||||
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
|
||||
case SyntaxKind.Constructor:
|
||||
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None);
|
||||
@@ -648,9 +846,10 @@ namespace ts {
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return bindAnonymousDeclaration(<TypeLiteralNode>node, SymbolFlags.TypeLiteral, "__type");
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return bindAnonymousDeclaration(<ObjectLiteralExpression>node, SymbolFlags.ObjectLiteral, "__object");
|
||||
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
checkStrictModeFunctionName(<FunctionExpression>node);
|
||||
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function");
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
@@ -756,6 +955,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindVariableDeclarationOrBindingElement(node: VariableDeclaration | BindingElement) {
|
||||
if (inStrictMode) {
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, node.name)
|
||||
}
|
||||
|
||||
if (!isBindingPattern(node.name)) {
|
||||
if (isBlockOrCatchScoped(node)) {
|
||||
bindBlockScopedVariableDeclaration(node);
|
||||
@@ -779,6 +982,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindParameter(node: ParameterDeclaration) {
|
||||
if (inStrictMode) {
|
||||
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
|
||||
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, node.name);
|
||||
}
|
||||
|
||||
if (isBindingPattern(node.name)) {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node));
|
||||
}
|
||||
|
||||
@@ -7734,7 +7734,7 @@ namespace ts {
|
||||
// Grammar checking
|
||||
let hasGrammarError = checkGrammarFunctionLikeDeclaration(node);
|
||||
if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) {
|
||||
checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node);
|
||||
checkGrammarForGenerator(node);
|
||||
}
|
||||
|
||||
// The identityMapper object is used to indicate that function expressions are wildcards
|
||||
@@ -7891,14 +7891,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkDeleteExpression(node: DeleteExpression): Type {
|
||||
// Grammar checking
|
||||
if (node.parserContextFlags & ParserContextFlags.StrictMode && node.expression.kind === SyntaxKind.Identifier) {
|
||||
// When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
|
||||
// UnaryExpression is a direct reference to a variable, function argument, or function name
|
||||
grammarErrorOnNode(node.expression, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode);
|
||||
}
|
||||
|
||||
let operandType = checkExpression(node.expression);
|
||||
checkExpression(node.expression);
|
||||
return booleanType;
|
||||
}
|
||||
|
||||
@@ -7913,14 +7906,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
|
||||
// Grammar checking
|
||||
// The identifier eval or arguments may not appear as the LeftHandSideExpression of an
|
||||
// Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression
|
||||
// operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator
|
||||
if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken)) {
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
|
||||
}
|
||||
|
||||
let operandType = checkExpression(node.operand);
|
||||
switch (node.operator) {
|
||||
case SyntaxKind.PlusToken:
|
||||
@@ -7947,12 +7932,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
|
||||
// Grammar checking
|
||||
// The identifier eval or arguments may not appear as the LeftHandSideExpression of an
|
||||
// Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression
|
||||
// operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator.
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
|
||||
|
||||
let operandType = checkExpression(node.operand);
|
||||
let ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
|
||||
if (ok) {
|
||||
@@ -8132,13 +8111,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) {
|
||||
// Grammar checking
|
||||
if (isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
|
||||
// ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
|
||||
// Assignment operator(11.13) or of a PostfixExpression(11.3)
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.left);
|
||||
}
|
||||
|
||||
let operator = node.operatorToken.kind;
|
||||
if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
|
||||
return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper);
|
||||
@@ -8580,11 +8552,9 @@ namespace ts {
|
||||
// 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)
|
||||
|
||||
// Grammar checking
|
||||
checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
|
||||
checkGrammarDecorators(node) || checkGrammarModifiers(node);
|
||||
|
||||
checkVariableLikeDeclaration(node);
|
||||
let func = getContainingFunction(node);
|
||||
@@ -9476,9 +9446,7 @@ namespace ts {
|
||||
|
||||
function checkFunctionDeclaration(node: FunctionDeclaration): void {
|
||||
if (produceDiagnostics) {
|
||||
checkFunctionLikeDeclaration(node) ||
|
||||
checkGrammarFunctionName(node.name) ||
|
||||
checkGrammarForGenerator(node);
|
||||
checkFunctionLikeDeclaration(node) || checkGrammarForGenerator(node);
|
||||
|
||||
checkCollisionWithCapturedSuperVariable(node, node.name);
|
||||
checkCollisionWithCapturedThisVariable(node, node.name);
|
||||
@@ -10305,12 +10273,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkWithStatement(node: WithStatement) {
|
||||
// Grammar checking for withStatement
|
||||
if (!checkGrammarStatementInAmbientContext(node)) {
|
||||
if (node.parserContextFlags & ParserContextFlags.StrictMode) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
|
||||
}
|
||||
}
|
||||
checkGrammarStatementInAmbientContext(node);
|
||||
|
||||
checkExpression(node.expression);
|
||||
error(node.expression, Diagnostics.All_symbols_within_a_with_block_will_be_resolved_to_any);
|
||||
@@ -10414,10 +10377,6 @@ namespace ts {
|
||||
grammarErrorOnNode(localSymbol.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, identifierName);
|
||||
}
|
||||
}
|
||||
|
||||
// It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the
|
||||
// Catch production is eval or arguments
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>catchClause.variableDeclaration.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13022,11 +12981,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarFunctionName(name: Node) {
|
||||
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
|
||||
return checkGrammarEvalOrArgumentsInStrictMode(name, <Identifier>name);
|
||||
}
|
||||
|
||||
function checkGrammarForInvalidQuestionMark(node: Declaration, questionToken: Node, message: DiagnosticMessage): boolean {
|
||||
if (questionToken) {
|
||||
return grammarErrorOnNode(questionToken, message);
|
||||
@@ -13039,7 +12993,6 @@ namespace ts {
|
||||
let GetAccessor = 2;
|
||||
let SetAccesor = 4;
|
||||
let GetOrSetAccessor = GetAccessor | SetAccesor;
|
||||
let inStrictMode = (node.parserContextFlags & ParserContextFlags.StrictMode) !== 0;
|
||||
|
||||
for (let prop of node.properties) {
|
||||
let name = prop.name;
|
||||
@@ -13086,9 +13039,7 @@ namespace ts {
|
||||
else {
|
||||
let existingKind = seen[(<Identifier>name).text];
|
||||
if (currentKind === Property && existingKind === Property) {
|
||||
if (inStrictMode) {
|
||||
grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) {
|
||||
if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) {
|
||||
@@ -13311,9 +13262,6 @@ namespace ts {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
|
||||
}
|
||||
}
|
||||
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
|
||||
// and its Identifier is eval or arguments
|
||||
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
|
||||
}
|
||||
|
||||
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
|
||||
@@ -13345,8 +13293,7 @@ namespace ts {
|
||||
|
||||
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
|
||||
// and its Identifier is eval or arguments
|
||||
return (checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name)) ||
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
|
||||
return checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name);
|
||||
}
|
||||
|
||||
function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean {
|
||||
@@ -13485,25 +13432,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarEvalOrArgumentsInStrictMode(contextNode: Node, name: Node): boolean {
|
||||
if (name && name.kind === SyntaxKind.Identifier) {
|
||||
let identifier = <Identifier>name;
|
||||
if (contextNode && (contextNode.parserContextFlags & ParserContextFlags.StrictMode) && isEvalOrArgumentsIdentifier(identifier)) {
|
||||
// We check first if the name is inside class declaration or class expression; if so give explicit message
|
||||
// otherwise report generic error message.
|
||||
let message = getAncestor(identifier, SyntaxKind.ClassDeclaration) || getAncestor(identifier, SyntaxKind.ClassExpression) ?
|
||||
Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode :
|
||||
Diagnostics.Invalid_use_of_0_in_strict_mode;
|
||||
return grammarErrorOnNode(identifier, message, declarationNameToString(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
|
||||
}
|
||||
|
||||
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
|
||||
if (node.typeParameters) {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
@@ -13613,13 +13541,8 @@ namespace ts {
|
||||
|
||||
function checkGrammarNumericLiteral(node: Identifier): boolean {
|
||||
// Grammar checking
|
||||
if (node.flags & NodeFlags.OctalLiteral) {
|
||||
if (node.parserContextFlags & ParserContextFlags.StrictMode) {
|
||||
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode);
|
||||
}
|
||||
else if (languageVersion >= ScriptTarget.ES5) {
|
||||
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);
|
||||
}
|
||||
if (node.flags & NodeFlags.OctalLiteral && languageVersion >= ScriptTarget.ES5) {
|
||||
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ namespace ts {
|
||||
token = nextToken();
|
||||
processReferenceComments(sourceFile);
|
||||
|
||||
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseStatement);
|
||||
sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement);
|
||||
Debug.assert(token === SyntaxKind.EndOfFileToken);
|
||||
sourceFile.endOfFileToken = parseTokenNode();
|
||||
|
||||
@@ -647,10 +647,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function setStrictModeContext(val: boolean) {
|
||||
setContextFlag(val, ParserContextFlags.StrictMode);
|
||||
}
|
||||
|
||||
function setDisallowInContext(val: boolean) {
|
||||
setContextFlag(val, ParserContextFlags.DisallowIn);
|
||||
}
|
||||
@@ -744,10 +740,6 @@ namespace ts {
|
||||
return (contextFlags & ParserContextFlags.Yield) !== 0;
|
||||
}
|
||||
|
||||
function inStrictModeContext() {
|
||||
return (contextFlags & ParserContextFlags.StrictMode) !== 0;
|
||||
}
|
||||
|
||||
function inGeneratorParameterContext() {
|
||||
return (contextFlags & ParserContextFlags.GeneratorParameter) !== 0;
|
||||
}
|
||||
@@ -1323,31 +1315,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Parses a list of elements
|
||||
function parseList<T extends Node>(kind: ParsingContext, checkForStrictMode: boolean, parseElement: () => T): NodeArray<T> {
|
||||
function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
|
||||
let saveParsingContext = parsingContext;
|
||||
parsingContext |= 1 << kind;
|
||||
let result = <NodeArray<T>>[];
|
||||
result.pos = getNodePos();
|
||||
let savedStrictModeContext = inStrictModeContext();
|
||||
|
||||
while (!isListTerminator(kind)) {
|
||||
if (isListElement(kind, /* inErrorRecovery */ false)) {
|
||||
let element = parseListElement(kind, parseElement);
|
||||
result.push(element);
|
||||
|
||||
// test elements only if we are not already in strict mode
|
||||
if (checkForStrictMode && !inStrictModeContext()) {
|
||||
if (isPrologueDirective(element)) {
|
||||
if (isUseStrictPrologueDirective(element)) {
|
||||
setStrictModeContext(true);
|
||||
checkForStrictMode = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkForStrictMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1356,22 +1334,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
setStrictModeContext(savedStrictModeContext);
|
||||
result.end = getNodeEnd();
|
||||
parsingContext = saveParsingContext;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
|
||||
function isUseStrictPrologueDirective(node: Node): boolean {
|
||||
Debug.assert(isPrologueDirective(node));
|
||||
let nodeText = getTextOfNodeFromSourceText(sourceText, (<ExpressionStatement>node).expression);
|
||||
|
||||
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
|
||||
// string to contain unicode escapes (as per ES5).
|
||||
return nodeText === '"use strict"' || nodeText === "'use strict'";
|
||||
}
|
||||
|
||||
function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T {
|
||||
let node = currentNode(parsingContext);
|
||||
if (node) {
|
||||
@@ -2276,7 +2243,7 @@ namespace ts {
|
||||
function parseObjectTypeMembers(): NodeArray<Declaration> {
|
||||
let members: NodeArray<Declaration>;
|
||||
if (parseExpected(SyntaxKind.OpenBraceToken)) {
|
||||
members = parseList(ParsingContext.TypeMembers, /*checkForStrictMode*/ false, parseTypeMember);
|
||||
members = parseList(ParsingContext.TypeMembers, parseTypeMember);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
@@ -2645,12 +2612,6 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inStrictModeContext()) {
|
||||
// If we're in strict mode, then 'yield' is a keyword, could only ever start
|
||||
// a yield expression.
|
||||
return true;
|
||||
}
|
||||
|
||||
// We're in a context where 'yield expr' is not allowed. However, if we can
|
||||
// definitely tell that the user was trying to parse a 'yield expr' and not
|
||||
// just a normal expr that start with a 'yield' identifier, then parse out
|
||||
@@ -2665,7 +2626,7 @@ namespace ts {
|
||||
// for now we just check if the next token is an identifier. More heuristics
|
||||
// can be added here later as necessary. We just need to make sure that we
|
||||
// don't accidently consume something legal.
|
||||
return lookAhead(nextTokenIsIdentifierOnSameLine);
|
||||
return lookAhead(nextTokenIsIdentifierOrKeywordOrNumberOnSameLine);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -3508,10 +3469,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
// STATEMENTS
|
||||
function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
let node = <Block>createNode(SyntaxKind.Block);
|
||||
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
|
||||
node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement);
|
||||
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
@@ -3531,7 +3492,7 @@ namespace ts {
|
||||
setDecoratorContext(false);
|
||||
}
|
||||
|
||||
let block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true, diagnosticMessage);
|
||||
let block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage);
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(true);
|
||||
@@ -3673,7 +3634,7 @@ namespace ts {
|
||||
parseExpected(SyntaxKind.CaseKeyword);
|
||||
node.expression = allowInAnd(parseExpression);
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -3681,7 +3642,7 @@ namespace ts {
|
||||
let node = <DefaultClause>createNode(SyntaxKind.DefaultClause);
|
||||
parseExpected(SyntaxKind.DefaultKeyword);
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -3697,7 +3658,7 @@ namespace ts {
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
let caseBlock = <CaseBlock>createNode(SyntaxKind.CaseBlock, scanner.getStartPos());
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
caseBlock.clauses = parseList(ParsingContext.SwitchClauses, /*checkForStrictMode*/ false, parseCaseOrDefaultClause);
|
||||
caseBlock.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
node.caseBlock = finishNode(caseBlock);
|
||||
return finishNode(node);
|
||||
@@ -3724,14 +3685,14 @@ namespace ts {
|
||||
let node = <TryStatement>createNode(SyntaxKind.TryStatement);
|
||||
|
||||
parseExpected(SyntaxKind.TryKeyword);
|
||||
node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
|
||||
node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
|
||||
node.catchClause = token === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;
|
||||
|
||||
// If we don't have a catch clause, then we must have a finally clause. Try to parse
|
||||
// one out no matter what.
|
||||
if (!node.catchClause || token === SyntaxKind.FinallyKeyword) {
|
||||
parseExpected(SyntaxKind.FinallyKeyword);
|
||||
node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
|
||||
node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
@@ -3745,7 +3706,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
result.block = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
|
||||
result.block = parseBlock(/*ignoreMissingOpenBrace*/ false);
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
@@ -3786,6 +3747,11 @@ namespace ts {
|
||||
return isIdentifierOrKeyword() && !scanner.hasPrecedingLineBreak();
|
||||
}
|
||||
|
||||
function nextTokenIsIdentifierOrKeywordOrNumberOnSameLine() {
|
||||
nextToken();
|
||||
return (isIdentifierOrKeyword() || token === SyntaxKind.NumericLiteral) && !scanner.hasPrecedingLineBreak();
|
||||
}
|
||||
|
||||
function isDeclaration(): boolean {
|
||||
while (true) {
|
||||
switch (token) {
|
||||
@@ -3913,16 +3879,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() {
|
||||
function nextTokenIsIdentifierOrStartOfDestructuring() {
|
||||
nextToken();
|
||||
return !scanner.hasPrecedingLineBreak() &&
|
||||
(isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken);
|
||||
return isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken;
|
||||
}
|
||||
|
||||
function isLetDeclaration() {
|
||||
// It is let declaration if in strict mode or next token is identifier\open bracket\open curly on same line.
|
||||
// otherwise it needs to be treated like identifier
|
||||
return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine);
|
||||
// In ES6 'let' always starts a lexical declaration if followed by an identifier or {
|
||||
// or [.
|
||||
return lookAhead(nextTokenIsIdentifierOrStartOfDestructuring);
|
||||
}
|
||||
|
||||
function parseStatement(): Statement {
|
||||
@@ -3930,7 +3895,7 @@ namespace ts {
|
||||
case SyntaxKind.SemicolonToken:
|
||||
return parseEmptyStatement();
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
|
||||
return parseBlock(/*ignoreMissingOpenBrace*/ false);
|
||||
case SyntaxKind.VarKeyword:
|
||||
return parseVariableStatement(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers*/ undefined);
|
||||
case SyntaxKind.LetKeyword:
|
||||
@@ -4448,10 +4413,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseClassDeclarationOrExpression(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, kind: SyntaxKind): ClassLikeDeclaration {
|
||||
// In ES6 specification, All parts of a ClassDeclaration or a ClassExpression are strict mode code
|
||||
let savedStrictModeContext = inStrictModeContext();
|
||||
setStrictModeContext(true);
|
||||
|
||||
var node = <ClassLikeDeclaration>createNode(kind, fullStart);
|
||||
node.decorators = decorators;
|
||||
setModifiers(node, modifiers);
|
||||
@@ -4474,9 +4435,7 @@ namespace ts {
|
||||
node.members = createMissingList<ClassElement>();
|
||||
}
|
||||
|
||||
var finishedNode = finishNode(node);
|
||||
setStrictModeContext(savedStrictModeContext);
|
||||
return finishedNode;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseHeritageClauses(isClassHeritageClause: boolean): NodeArray<HeritageClause> {
|
||||
@@ -4494,7 +4453,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseHeritageClausesWorker() {
|
||||
return parseList(ParsingContext.HeritageClauses, /*checkForStrictMode*/ false, parseHeritageClause);
|
||||
return parseList(ParsingContext.HeritageClauses, parseHeritageClause);
|
||||
}
|
||||
|
||||
function parseHeritageClause() {
|
||||
@@ -4524,7 +4483,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseClassMembers() {
|
||||
return parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassElement);
|
||||
return parseList(ParsingContext.ClassMembers, parseClassElement);
|
||||
}
|
||||
|
||||
function parseInterfaceDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): InterfaceDeclaration {
|
||||
@@ -4582,7 +4541,7 @@ namespace ts {
|
||||
function parseModuleBlock(): ModuleBlock {
|
||||
let node = <ModuleBlock>createNode(SyntaxKind.ModuleBlock, scanner.getStartPos());
|
||||
if (parseExpected(SyntaxKind.OpenBraceToken)) {
|
||||
node.statements = parseList(ParsingContext.BlockStatements, /*checkForStrictMode*/ false, parseStatement);
|
||||
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -362,10 +362,6 @@ namespace ts {
|
||||
export const enum ParserContextFlags {
|
||||
None = 0,
|
||||
|
||||
// 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.
|
||||
StrictMode = 1 << 0,
|
||||
|
||||
// If this node was parsed in a context where 'in-expressions' are not allowed.
|
||||
DisallowIn = 1 << 1,
|
||||
|
||||
@@ -388,7 +384,7 @@ namespace ts {
|
||||
JavaScriptFile = 1 << 6,
|
||||
|
||||
// Context flags set directly by the parser.
|
||||
ParserGeneratedFlags = StrictMode | DisallowIn | Yield | GeneratorParameter | Decorator | ThisNodeHasError,
|
||||
ParserGeneratedFlags = DisallowIn | Yield | GeneratorParameter | Decorator | ThisNodeHasError,
|
||||
|
||||
// Context flags computed by aggregating child flags upwards.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user