diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index efceaeb5967..b88f08dc6ca 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -897,6 +897,23 @@ module ts { // understand when these values should be changed versus when they should be inherited. var strictModeContext = false; var disallowInContext = false; + var contextFlags: number = 0; + + function updateContextFlags() { + contextFlags = + (strictModeContext ? NodeFlags.ParsedInStrictModeContext : 0) | + (disallowInContext ? NodeFlags.ParsedInDisallowInContext : 0); + } + + function setStrictModeContext(val: boolean) { + strictModeContext = val; + updateContextFlags(); + } + + function setDisallowInContext(val: boolean) { + disallowInContext = val; + updateContextFlags(); + } function allowInAnd(func: () => T): T { if (disallowInContext) { @@ -922,10 +939,6 @@ module ts { return result; } - function setDisallowInContext(val: boolean) { - disallowInContext = val; - } - function getLineStarts(): number[] { return lineStarts || (lineStarts = computeLineStarts(sourceText)); } @@ -1108,12 +1121,8 @@ module ts { function finishNode(node: T): T { node.end = scanner.getStartPos(); - if (strictModeContext) { - node.flags |= NodeFlags.ParsedInStrictModeContext; - } - - if (disallowInContext) { - node.flags |= NodeFlags.ParsedInDisallowInContext + if (contextFlags) { + node.parserContextFlags = contextFlags; } return node; @@ -1310,7 +1319,7 @@ module ts { if (!strictModeContext && checkForStrictMode) { if (isPrologueDirective(element)) { if (isUseStrictPrologueDirective(element)) { - strictModeContext = true; + setStrictModeContext(true); checkForStrictMode = false; } } @@ -1327,7 +1336,7 @@ module ts { nextToken(); } } - strictModeContext = savedStrictModeContext; + setStrictModeContext(savedStrictModeContext); result.end = getNodeEnd(); parsingContext = saveParsingContext; return result; @@ -3750,7 +3759,7 @@ module ts { } function checkBinaryExpression(node: BinaryExpression) { - if (node.flags & NodeFlags.ParsedInStrictModeContext) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext) { if (isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operator)) { if (isEvalOrArgumentsIdentifier(node.left)) { // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an @@ -3902,7 +3911,7 @@ module ts { var colonStart = skipTrivia(sourceText, node.variable.end); return grammarErrorAtPos(colonStart, ":".length, Diagnostics.Catch_clause_parameter_cannot_have_a_type_annotation); } - if (node.flags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.variable)) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.variable)) { // 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 return reportInvalidUseInStrictMode(node.variable); @@ -4022,7 +4031,7 @@ module ts { } function checkFunctionName(name: Node) { - if (name && name.flags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(name)) { + if (name && name.parserContextFlags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(name)) { // It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the // Identifier of a FunctionLikeDeclaration or FunctionExpression or as a formal parameter name(13.1) return reportInvalidUseInStrictMode(name); @@ -4143,7 +4152,7 @@ module ts { var GetAccessor = 2; var SetAccesor = 4; var GetOrSetAccessor = GetAccessor | SetAccesor; - var inStrictMode = (node.flags & NodeFlags.ParsedInStrictModeContext) !== 0; + var inStrictMode = (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext) !== 0; for (var i = 0, n = node.properties.length; i < n; i++) { var prop = node.properties[i]; @@ -4207,7 +4216,7 @@ module ts { function checkNumericLiteral(node: LiteralExpression): boolean { if (node.flags & NodeFlags.OctalLiteral) { - if (node.flags & NodeFlags.ParsedInStrictModeContext) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext) { return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode); } else if (languageVersion >= ScriptTarget.ES5) { @@ -4351,7 +4360,7 @@ module ts { // 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.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.name)) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.name)) { return reportInvalidUseInStrictMode(node.name); } } @@ -4410,13 +4419,13 @@ module ts { // 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.flags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.operand)) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.operand)) { return reportInvalidUseInStrictMode(node.operand); } } function checkPrefixOperator(node: UnaryExpression) { - if (node.flags & NodeFlags.ParsedInStrictModeContext) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext) { // 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 @@ -4601,7 +4610,7 @@ module ts { if (!inAmbientContext && !node.initializer && isConst(node)) { return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); } - if (node.flags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.name)) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext && isEvalOrArgumentsIdentifier(node.name)) { // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code // and its Identifier is eval or arguments return reportInvalidUseInStrictMode(node.name); @@ -4663,7 +4672,7 @@ module ts { } function checkWithStatement(node: WithStatement): boolean { - if (node.flags & NodeFlags.ParsedInStrictModeContext) { + if (node.parserContextFlags & NodeFlags.ParsedInStrictModeContext) { // Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such // a context is an return grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ee01e40b66a..6e4efbc3926 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -285,6 +285,9 @@ module ts { export interface Node extends TextRange { kind: SyntaxKind; flags: NodeFlags; + // Specific context the parser was in when this node was created. Normally undefined. + // Only set when the parser was in some interesting context (like async/yield). + parserContextFlags?: NodeFlags; id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding) symbol?: Symbol; // Symbol declared by node (initialized by binding)