diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 5764c316090..bffd3179e83 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1239,6 +1239,8 @@ namespace ts { export interface ObjectAllocator { getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node; + getTokenConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Token; + getIdentifierConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Token; getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile; getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; @@ -1268,6 +1270,8 @@ namespace ts { export let objectAllocator: ObjectAllocator = { getNodeConstructor: () => Node, + getTokenConstructor: () => Node, + getIdentifierConstructor: () => Node, getSourceFileConstructor: () => Node, getSymbolConstructor: () => Symbol, getTypeConstructor: () => Type, diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e12ff7c87dc..2eae2c4025e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5,12 +5,20 @@ namespace ts { /* @internal */ export let parseTime = 0; let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { if (kind === SyntaxKind.SourceFile) { return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); } + else if (kind === SyntaxKind.Identifier) { + return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end); + } + else if (kind < SyntaxKind.FirstNode) { + return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end); + } else { return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); } @@ -466,6 +474,8 @@ namespace ts { // capture constructors in 'initializeState' to avoid null checks let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let sourceFile: SourceFile; @@ -576,6 +586,8 @@ namespace ts { function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, scriptKind: ScriptKind) { NodeConstructor = objectAllocator.getNodeConstructor(); + TokenConstructor = objectAllocator.getTokenConstructor(); + IdentifierConstructor = objectAllocator.getIdentifierConstructor(); SourceFileConstructor = objectAllocator.getSourceFileConstructor(); sourceText = _sourceText; @@ -1018,13 +1030,15 @@ namespace ts { } // note: this function creates only node - function createNode(kind: SyntaxKind, pos?: number): Node { + function createNode(kind: SyntaxKind, pos?: number): Node | Token | Identifier { nodeCount++; if (!(pos >= 0)) { pos = scanner.getStartPos(); } - return new NodeConstructor(kind, pos, pos); + return kind >= SyntaxKind.FirstNode ? new NodeConstructor(kind, pos, pos) : + kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, pos, pos) : + new TokenConstructor(kind, pos, pos); } function finishNode(node: T, end?: number): T { @@ -5096,7 +5110,7 @@ namespace ts { } flags |= modifierToFlag(modifierKind); - modifiers.push(finishNode(createNode(modifierKind, modifierStart))); + modifiers.push(finishNode(createNode(modifierKind, modifierStart))); } if (modifiers) { modifiers.flags = flags; @@ -5115,7 +5129,7 @@ namespace ts { modifiers = []; modifiers.pos = modifierStart; flags |= modifierToFlag(modifierKind); - modifiers.push(finishNode(createNode(modifierKind, modifierStart))); + modifiers.push(finishNode(createNode(modifierKind, modifierStart))); modifiers.flags = flags; modifiers.end = scanner.getStartPos(); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3a3a937ade7..de4f6bc526c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -472,6 +472,10 @@ namespace ts { flags: NodeFlags; } + export interface Token extends Node { + __tokenTag: any; + } + // @kind(SyntaxKind.AbstractKeyword) // @kind(SyntaxKind.AsyncKeyword) // @kind(SyntaxKind.ConstKeyword) @@ -482,7 +486,7 @@ namespace ts { // @kind(SyntaxKind.PrivateKeyword) // @kind(SyntaxKind.ProtectedKeyword) // @kind(SyntaxKind.StaticKeyword) - export interface Modifier extends Node { } + export interface Modifier extends Token { } // @kind(SyntaxKind.Identifier) export interface Identifier extends PrimaryExpression { diff --git a/src/services/services.ts b/src/services/services.ts index 8c69b66c7d8..d9e025cf8fd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -180,9 +180,10 @@ namespace ts { ]; let jsDocCompletionEntries: CompletionEntry[]; - function createNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags, parent?: Node): NodeObject { - const node = new NodeObject(kind, pos, end); - node.flags = flags; + function createNode(kind: SyntaxKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject { + const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) : + kind === SyntaxKind.Identifier ? new IdentifierObject(kind, pos, end) : + new TokenObject(kind, pos, end); node.parent = parent; return node; } @@ -197,11 +198,11 @@ namespace ts { private _children: Node[]; constructor(kind: SyntaxKind, pos: number, end: number) { - this.kind = kind; this.pos = pos; this.end = end; this.flags = NodeFlags.None; this.parent = undefined; + this.kind = kind; } public getSourceFile(): SourceFile { @@ -246,7 +247,7 @@ namespace ts { const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan(); const textPos = scanner.getTextPos(); if (textPos <= end) { - nodes.push(createNode(token, pos, textPos, 0, this)); + nodes.push(createNode(token, pos, textPos, this)); } pos = textPos; } @@ -254,7 +255,7 @@ namespace ts { } private createSyntaxList(nodes: NodeArray): Node { - const list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, 0, this); + const list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, this); list._children = []; let pos = nodes.pos; @@ -345,6 +346,95 @@ namespace ts { } } + class TokenOrIdentifierObject implements Token { + public kind: SyntaxKind; + public pos: number; + public end: number; + public flags: NodeFlags; + public parent: Node; + public jsDocComments: JSDocComment[]; + public __tokenTag: any; + + constructor(pos: number, end: number) { + // Set properties in same order as NodeObject + this.pos = pos; + this.end = end; + this.flags = NodeFlags.None; + this.parent = undefined; + } + + public getSourceFile(): SourceFile { + return getSourceFileOfNode(this); + } + + public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number { + return getTokenPosOfNode(this, sourceFile, includeJsDocComment); + } + + public getFullStart(): number { + return this.pos; + } + + public getEnd(): number { + return this.end; + } + + public getWidth(sourceFile?: SourceFile): number { + return this.getEnd() - this.getStart(sourceFile); + } + + public getFullWidth(): number { + return this.end - this.pos; + } + + public getLeadingTriviaWidth(sourceFile?: SourceFile): number { + return this.getStart(sourceFile) - this.pos; + } + + public getFullText(sourceFile?: SourceFile): string { + return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end); + } + + public getText(sourceFile?: SourceFile): string { + return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); + } + + public getChildCount(sourceFile?: SourceFile): number { + return 0; + } + + public getChildAt(index: number, sourceFile?: SourceFile): Node { + return undefined; + } + + public getChildren(sourceFile?: SourceFile): Node[] { + return emptyArray; + } + + public getFirstToken(sourceFile?: SourceFile): Node { + return undefined; + } + + public getLastToken(sourceFile?: SourceFile): Node { + return undefined; + } + } + + class TokenObject extends TokenOrIdentifierObject { + public kind: SyntaxKind; + constructor(kind: SyntaxKind, pos: number, end: number) { + super(pos, end); + this.kind = kind; + } + } + + class IdentifierObject extends TokenOrIdentifierObject { + constructor(kind: SyntaxKind, pos: number, end: number) { + super(pos, end); + } + } + IdentifierObject.prototype.kind = SyntaxKind.Identifier; + class SymbolObject implements Symbol { flags: SymbolFlags; name: string; @@ -8694,6 +8784,8 @@ namespace ts { function initializeServices() { objectAllocator = { getNodeConstructor: () => NodeObject, + getTokenConstructor: () => TokenObject, + getIdentifierConstructor: () => IdentifierObject, getSourceFileConstructor: () => SourceFileObject, getSymbolConstructor: () => SymbolObject, getTypeConstructor: () => TypeObject,