From 83859c0d91b3fb23ed5e7588d79de3a6bbae6b00 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 31 Jan 2016 08:45:14 -0800 Subject: [PATCH] Merge ParserContextFlags into NodeFlags --- src/compiler/checker.ts | 16 ++++----- src/compiler/parser.ts | 58 ++++++++++++++++---------------- src/compiler/types.ts | 69 ++++++++++++--------------------------- src/compiler/utilities.ts | 14 ++++---- src/harness/harness.ts | 2 +- 5 files changed, 66 insertions(+), 93 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 88f000c5a74..fafcffbe582 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2634,7 +2634,7 @@ namespace ts { // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type { - if (declaration.parserContextFlags & ParserContextFlags.JavaScriptFile) { + if (declaration.parserContextFlags & NodeFlags.JavaScriptFile) { // If this is a variable in a JavaScript file, then use the JSDoc type (if it has // one as its type), otherwise fallback to the below standard TS codepaths to // try to figure it out. @@ -3981,7 +3981,7 @@ namespace ts { } function getTypeParametersFromJSDocTemplate(declaration: SignatureDeclaration): TypeParameter[] { - if (declaration.parserContextFlags & ParserContextFlags.JavaScriptFile) { + if (declaration.parserContextFlags & NodeFlags.JavaScriptFile) { const templateTag = getJSDocTemplateTag(declaration); if (templateTag) { return getTypeParametersFromDeclaration(templateTag.typeParameters); @@ -4015,7 +4015,7 @@ namespace ts { } function isOptionalParameter(node: ParameterDeclaration) { - if (node.parserContextFlags & ParserContextFlags.JavaScriptFile) { + if (node.parserContextFlags & NodeFlags.JavaScriptFile) { if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) { return true; } @@ -4124,7 +4124,7 @@ namespace ts { returnType = getTypeFromTypeNode(declaration.type); } else { - if (declaration.parserContextFlags & ParserContextFlags.JavaScriptFile) { + if (declaration.parserContextFlags & NodeFlags.JavaScriptFile) { const type = getReturnTypeFromJSDocComment(declaration); if (type && type !== unknownType) { returnType = type; @@ -7183,7 +7183,7 @@ namespace ts { } } - if (node.parserContextFlags & ParserContextFlags.Await) { + if (node.parserContextFlags & NodeFlags.Await) { getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments; } } @@ -10783,7 +10783,7 @@ namespace ts { function checkAwaitExpression(node: AwaitExpression): Type { // Grammar checking if (produceDiagnostics) { - if (!(node.parserContextFlags & ParserContextFlags.Await)) { + if (!(node.parserContextFlags & NodeFlags.Await)) { grammarErrorOnFirstToken(node, Diagnostics.await_expression_is_only_allowed_within_an_async_function); } @@ -11239,7 +11239,7 @@ namespace ts { function checkYieldExpression(node: YieldExpression): Type { // Grammar checking if (produceDiagnostics) { - if (!(node.parserContextFlags & ParserContextFlags.Yield) || isYieldExpressionInClass(node)) { + if (!(node.parserContextFlags & NodeFlags.Yield) || isYieldExpressionInClass(node)) { grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body); } @@ -13701,7 +13701,7 @@ namespace ts { function checkWithStatement(node: WithStatement) { // Grammar checking for withStatement if (!checkGrammarStatementInAmbientContext(node)) { - if (node.parserContextFlags & ParserContextFlags.Await) { + if (node.parserContextFlags & NodeFlags.Await) { grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_an_async_function_block); } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4fd81ed246f..bbf1c2bddac 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -438,7 +438,7 @@ namespace ts { // Share a single scanner across all calls to parse a source file. This helps speed things // up by avoiding the cost of creating/compiling scanners over and over again. const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); - const disallowInAndDecoratorContext = ParserContextFlags.DisallowIn | ParserContextFlags.Decorator; + const disallowInAndDecoratorContext = NodeFlags.DisallowIn | NodeFlags.Decorator; // capture constructors in 'initializeState' to avoid null checks let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; @@ -502,7 +502,7 @@ namespace ts { // Note: it should not be necessary to save/restore these flags during speculative/lookahead // parsing. These context flags are naturally stored and restored through normal recursive // descent parsing and unwinding. - let contextFlags: ParserContextFlags; + let contextFlags: NodeFlags; // Whether or not we've had a parse error since creating the last AST node. If we have // encountered an error, it will be stored on the next AST node we create. Parse errors @@ -562,7 +562,7 @@ namespace ts { identifierCount = 0; nodeCount = 0; - contextFlags = isJavaScriptFile ? ParserContextFlags.JavaScriptFile : ParserContextFlags.None; + contextFlags = isJavaScriptFile ? NodeFlags.JavaScriptFile : NodeFlags.None; parseErrorBeforeNextFinishedNode = false; // Initialize and prime the scanner before parsing the source elements. @@ -588,8 +588,8 @@ namespace ts { function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean): SourceFile { sourceFile = createSourceFile(fileName, languageVersion); - if (contextFlags & ParserContextFlags.JavaScriptFile) { - sourceFile.parserContextFlags = ParserContextFlags.JavaScriptFile; + if (contextFlags & NodeFlags.JavaScriptFile) { + sourceFile.parserContextFlags = NodeFlags.JavaScriptFile; } // Prime the scanner. @@ -616,7 +616,7 @@ namespace ts { function addJSDocComment(node: T): T { - if (contextFlags & ParserContextFlags.JavaScriptFile) { + if (contextFlags & NodeFlags.JavaScriptFile) { const comments = getLeadingCommentRangesOfNode(node, sourceFile); if (comments) { for (const comment of comments) { @@ -672,7 +672,7 @@ namespace ts { return sourceFile; } - function setContextFlag(val: boolean, flag: ParserContextFlags) { + function setContextFlag(val: boolean, flag: NodeFlags) { if (val) { contextFlags |= flag; } @@ -682,22 +682,22 @@ namespace ts { } function setDisallowInContext(val: boolean) { - setContextFlag(val, ParserContextFlags.DisallowIn); + setContextFlag(val, NodeFlags.DisallowIn); } function setYieldContext(val: boolean) { - setContextFlag(val, ParserContextFlags.Yield); + setContextFlag(val, NodeFlags.Yield); } function setDecoratorContext(val: boolean) { - setContextFlag(val, ParserContextFlags.Decorator); + setContextFlag(val, NodeFlags.Decorator); } function setAwaitContext(val: boolean) { - setContextFlag(val, ParserContextFlags.Await); + setContextFlag(val, NodeFlags.Await); } - function doOutsideOfContext(context: ParserContextFlags, func: () => T): T { + function doOutsideOfContext(context: NodeFlags, func: () => T): T { // contextFlagsToClear will contain only the context flags that are // currently set that we need to temporarily clear // We don't just blindly reset to the previous flags to ensure @@ -718,7 +718,7 @@ namespace ts { return func(); } - function doInsideOfContext(context: ParserContextFlags, func: () => T): T { + function doInsideOfContext(context: NodeFlags, func: () => T): T { // contextFlagsToSet will contain only the context flags that // are not currently set that we need to temporarily enable. // We don't just blindly reset to the previous flags to ensure @@ -740,51 +740,51 @@ namespace ts { } function allowInAnd(func: () => T): T { - return doOutsideOfContext(ParserContextFlags.DisallowIn, func); + return doOutsideOfContext(NodeFlags.DisallowIn, func); } function disallowInAnd(func: () => T): T { - return doInsideOfContext(ParserContextFlags.DisallowIn, func); + return doInsideOfContext(NodeFlags.DisallowIn, func); } function doInYieldContext(func: () => T): T { - return doInsideOfContext(ParserContextFlags.Yield, func); + return doInsideOfContext(NodeFlags.Yield, func); } function doInDecoratorContext(func: () => T): T { - return doInsideOfContext(ParserContextFlags.Decorator, func); + return doInsideOfContext(NodeFlags.Decorator, func); } function doInAwaitContext(func: () => T): T { - return doInsideOfContext(ParserContextFlags.Await, func); + return doInsideOfContext(NodeFlags.Await, func); } function doOutsideOfAwaitContext(func: () => T): T { - return doOutsideOfContext(ParserContextFlags.Await, func); + return doOutsideOfContext(NodeFlags.Await, func); } function doInYieldAndAwaitContext(func: () => T): T { - return doInsideOfContext(ParserContextFlags.Yield | ParserContextFlags.Await, func); + return doInsideOfContext(NodeFlags.Yield | NodeFlags.Await, func); } - function inContext(flags: ParserContextFlags) { + function inContext(flags: NodeFlags) { return (contextFlags & flags) !== 0; } function inYieldContext() { - return inContext(ParserContextFlags.Yield); + return inContext(NodeFlags.Yield); } function inDisallowInContext() { - return inContext(ParserContextFlags.DisallowIn); + return inContext(NodeFlags.DisallowIn); } function inDecoratorContext() { - return inContext(ParserContextFlags.Decorator); + return inContext(NodeFlags.Decorator); } function inAwaitContext() { - return inContext(ParserContextFlags.Await); + return inContext(NodeFlags.Await); } function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { @@ -1004,7 +1004,7 @@ namespace ts { // flag so that we don't mark any subsequent nodes. if (parseErrorBeforeNextFinishedNode) { parseErrorBeforeNextFinishedNode = false; - node.parserContextFlags |= ParserContextFlags.ThisNodeHasError; + node.parserContextFlags |= NodeFlags.ThisNodeHasError; } return node; @@ -1453,7 +1453,7 @@ namespace ts { // differently depending on what mode it is in. // // This also applies to all our other context flags as well. - const nodeContextFlags = node.parserContextFlags & ParserContextFlags.ParserGeneratedFlags; + const nodeContextFlags = node.parserContextFlags & NodeFlags.ParserGeneratedFlags; if (nodeContextFlags !== contextFlags) { return undefined; } @@ -2512,7 +2512,7 @@ namespace ts { function parseType(): TypeNode { // The rules about 'yield' only apply to actual code/expression contexts. They don't // apply to 'type' contexts. So we disable these parameters here before moving on. - return doOutsideOfContext(ParserContextFlags.TypeExcludesFlags, parseTypeWorker); + return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker); } function parseTypeWorker(): TypeNode { @@ -4785,7 +4785,7 @@ namespace ts { // The checker may still error in the static case to explicitly disallow the yield expression. property.initializer = modifiers && modifiers.flags & NodeFlags.Static ? allowInAnd(parseNonParameterInitializer) - : doOutsideOfContext(ParserContextFlags.Yield | ParserContextFlags.DisallowIn, parseNonParameterInitializer); + : doOutsideOfContext(NodeFlags.Yield | NodeFlags.DisallowIn, parseNonParameterInitializer); parseSemicolon(); return finishNode(property); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4421a882121..4b619041cb8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -381,18 +381,26 @@ namespace ts { Abstract = 1 << 7, // Class/Method/ConstructSignature Async = 1 << 8, // Property/Method/Function Default = 1 << 9, // Function/Class (export default declaration) - Let = 1 << 13, // Variable declaration - Const = 1 << 14, // Variable declaration - Namespace = 1 << 16, // Namespace declaration - ExportContext = 1 << 17, // Export context (initialized by binding) - ContainsThis = 1 << 18, // Interface contains references to "this" - HasImplicitReturn = 1 << 19, // If function implicitly returns on one of codepaths (initialized by binding) - HasExplicitReturn = 1 << 20, // If function has explicit reachable return on one of codepaths (initialized by binding) - GlobalAugmentation = 1 << 21, // Set if module declaration is an augmentation for the global scope - HasClassExtends = 1 << 22, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding) - HasDecorators = 1 << 23, // If the file has decorators (initialized by binding) - HasParamDecorators = 1 << 24, // If the file has parameter decorators (initialized by binding) - HasAsyncFunctions = 1 << 25, // If the file has async functions (initialized by binding) + Let = 1 << 10, // Variable declaration + Const = 1 << 11, // Variable declaration + Namespace = 1 << 12, // Namespace declaration + ExportContext = 1 << 13, // Export context (initialized by binding) + ContainsThis = 1 << 14, // Interface contains references to "this" + HasImplicitReturn = 1 << 15, // If function implicitly returns on one of codepaths (initialized by binding) + HasExplicitReturn = 1 << 16, // If function has explicit reachable return on one of codepaths (initialized by binding) + GlobalAugmentation = 1 << 17, // Set if module declaration is an augmentation for the global scope + HasClassExtends = 1 << 18, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding) + HasDecorators = 1 << 19, // If the file has decorators (initialized by binding) + HasParamDecorators = 1 << 20, // If the file has parameter decorators (initialized by binding) + HasAsyncFunctions = 1 << 21, // If the file has async functions (initialized by binding) + DisallowIn = 1 << 22, // If node was parsed in a context where 'in-expressions' are not allowed + Yield = 1 << 23, // If node was parsed in the 'yield' context created when parsing a generator + Decorator = 1 << 24, // If node was parsed as part of a decorator + Await = 1 << 25, // If node was parsed in the 'await' context created when parsing an async function + ThisNodeHasError = 1 << 26, // If the parser encountered an error when parsing the code that created this node + JavaScriptFile = 1 << 27, // If node was parsed in a JavaScript + ThisNodeOrAnySubNodesHasError = 1 << 28, // If this node or any of its children had an error + HasAggregatedChildData = 1 << 29, // If we've computed data from children and cached it in this node Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async, AccessibilityModifier = Public | Private | Protected, @@ -400,47 +408,12 @@ namespace ts { ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn, EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions, - } - - /* @internal */ - export const enum ParserContextFlags { - None = 0, - - // If this node was parsed in a context where 'in-expressions' are not allowed. - DisallowIn = 1 << 0, - - // If this node was parsed in the 'yield' context created when parsing a generator. - Yield = 1 << 1, - - // If this node was parsed as part of a decorator - Decorator = 1 << 2, - - // If this node was parsed in the 'await' context created when parsing an async function. - Await = 1 << 3, - - // If the parser encountered an error when parsing the code that created this node. Note - // the parser only sets this directly on the node it creates right after encountering the - // error. - ThisNodeHasError = 1 << 4, - - // This node was parsed in a JavaScript file and can be processed differently. For example - // its type can be specified usign a JSDoc comment. - JavaScriptFile = 1 << 5, // Context flags set directly by the parser. ParserGeneratedFlags = DisallowIn | Yield | Decorator | ThisNodeHasError | Await, // Exclude these flags when parsing a Type TypeExcludesFlags = Yield | Await, - - // Context flags computed by aggregating child flags upwards. - - // Used during incremental parsing to determine if this node or any of its children had an - // error. Computed only once and then cached. - ThisNodeOrAnySubNodesHasError = 1 << 6, - - // Used to know if we've computed data from children and cached it in this node. - HasAggregatedChildData = 1 << 7 } export const enum JsxFlags { @@ -470,7 +443,7 @@ namespace ts { 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). - /* @internal */ parserContextFlags?: ParserContextFlags; + /* @internal */ parserContextFlags?: NodeFlags; decorators?: NodeArray; // Array of decorators (in document order) modifiers?: ModifiersArray; // Array of modifiers /* @internal */ id?: number; // Unique id (used to look up NodeLinks) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7042200ba8e..9cb1b7e784e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -121,26 +121,26 @@ namespace ts { // Returns true if this node contains a parse error anywhere underneath it. export function containsParseError(node: Node): boolean { aggregateChildData(node); - return (node.parserContextFlags & ParserContextFlags.ThisNodeOrAnySubNodesHasError) !== 0; + return (node.parserContextFlags & NodeFlags.ThisNodeOrAnySubNodesHasError) !== 0; } function aggregateChildData(node: Node): void { - if (!(node.parserContextFlags & ParserContextFlags.HasAggregatedChildData)) { + if (!(node.parserContextFlags & NodeFlags.HasAggregatedChildData)) { // A node is considered to contain a parse error if: // a) the parser explicitly marked that it had an error // b) any of it's children reported that it had an error. - const thisNodeOrAnySubNodesHasError = ((node.parserContextFlags & ParserContextFlags.ThisNodeHasError) !== 0) || + const thisNodeOrAnySubNodesHasError = ((node.parserContextFlags & NodeFlags.ThisNodeHasError) !== 0) || forEachChild(node, containsParseError); // If so, mark ourselves accordingly. if (thisNodeOrAnySubNodesHasError) { - node.parserContextFlags |= ParserContextFlags.ThisNodeOrAnySubNodesHasError; + node.parserContextFlags |= NodeFlags.ThisNodeOrAnySubNodesHasError; } // Also mark that we've propogated the child information to this node. This way we can // always consult the bit directly on this node without needing to check its children // again. - node.parserContextFlags |= ParserContextFlags.HasAggregatedChildData; + node.parserContextFlags |= NodeFlags.HasAggregatedChildData; } } @@ -1078,7 +1078,7 @@ namespace ts { } export function isInJavaScriptFile(node: Node): boolean { - return node && !!(node.parserContextFlags & ParserContextFlags.JavaScriptFile); + return node && !!(node.parserContextFlags & NodeFlags.JavaScriptFile); } /** @@ -1266,7 +1266,7 @@ namespace ts { export function isRestParameter(node: ParameterDeclaration) { if (node) { - if (node.parserContextFlags & ParserContextFlags.JavaScriptFile) { + if (node.parserContextFlags & NodeFlags.JavaScriptFile) { if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) { return true; } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 2b0c95c0a61..6bc46667fed 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -284,7 +284,7 @@ namespace Utils { // Clear the flag that are produced by aggregating child values.. That is ephemeral // data we don't care about in the dump. We only care what the parser set directly // on the ast. - let value = n.parserContextFlags & ts.ParserContextFlags.ParserGeneratedFlags; + let value = n.parserContextFlags & ts.NodeFlags.ParserGeneratedFlags; if (value) { o[propertyName] = getParserContextFlagName(value); }