mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
WIP parser migration to factory
This commit is contained in:
parent
c55b9ffe83
commit
1bb706ed05
@ -4,19 +4,29 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
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;
|
||||
|
||||
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
|
||||
const ConstructorForKind = kind === SyntaxKind.SourceFile
|
||||
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
|
||||
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
|
||||
function getConstructorForKind(kind: SyntaxKind): new (kind: SyntaxKind, pos: number, end: number) => Node {
|
||||
if (kind === SyntaxKind.SourceFile) {
|
||||
return SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor());
|
||||
}
|
||||
if (kind === SyntaxKind.Identifier) {
|
||||
return IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor());
|
||||
}
|
||||
if (kind < SyntaxKind.FirstNode) {
|
||||
return TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor());
|
||||
}
|
||||
return NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor());
|
||||
}
|
||||
|
||||
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
|
||||
const ConstructorForKind = getConstructorForKind(kind);
|
||||
const node = location
|
||||
? new ConstructorForKind(kind, location.pos, location.end)
|
||||
: new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1);
|
||||
|
||||
node.flags = flags | NodeFlags.Synthesized;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -211,6 +221,13 @@ namespace ts {
|
||||
|
||||
// Names
|
||||
|
||||
export function createQualifiedName(left: EntityName, right: Identifier, location?: TextRange) {
|
||||
const node = <QualifiedName>createNode(SyntaxKind.QualifiedName, location);
|
||||
node.left = left;
|
||||
node.right = right;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createComputedPropertyName(expression: Expression, location?: TextRange) {
|
||||
const node = <ComputedPropertyName>createNode(SyntaxKind.ComputedPropertyName, location);
|
||||
node.expression = expression;
|
||||
@ -225,6 +242,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Signature elements
|
||||
export function createTypeParameter(name: Identifier, constraintOrExpression: TypeNode | Expression) {
|
||||
let constraint: TypeNode;
|
||||
let expression: Expression;
|
||||
if (constraint) {
|
||||
if (isTypeNode(constraintOrExpression)) {
|
||||
constraint = constraintOrExpression;
|
||||
}
|
||||
else {
|
||||
expression = constraintOrExpression;
|
||||
}
|
||||
}
|
||||
|
||||
const node = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
|
||||
node.name = name;
|
||||
node.constraint = constraint;
|
||||
node.expression = expression;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createParameter(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: string | Identifier | BindingPattern, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter, location, flags);
|
||||
@ -341,6 +376,28 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
// Types
|
||||
|
||||
export function createTypePredicate(parameterName: Identifier | ThisTypeNode, type: TypeNode) {
|
||||
const node = <TypePredicateNode>createNode(SyntaxKind.TypePredicate, /*location*/ undefined);
|
||||
node.parameterName = parameterName;
|
||||
node.type = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTypeReference(typeName: EntityName, typeArguments: TypeNode[]) {
|
||||
const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference, /*location*/ undefined);
|
||||
node.typeName = typeName;
|
||||
node.typeArguments = typeArguments ? createNodeArray(typeArguments) : undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTypeQuery(exprName: EntityName) {
|
||||
const node = <TypeQueryNode>createNode(SyntaxKind.TypeQuery, /*location*/ undefined);
|
||||
node.exprName = exprName;
|
||||
return node;
|
||||
}
|
||||
|
||||
// Binding Patterns
|
||||
|
||||
export function createObjectBindingPattern(elements: BindingElement[], location?: TextRange) {
|
||||
|
||||
@ -1119,6 +1119,46 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function makeParseNode<T extends Node>(node: T, pos?: number, end?: number): T {
|
||||
nodeCount++;
|
||||
node.pos = pos === undefined ? scanner.getStartPos() : pos;
|
||||
node.end = end === undefined ? scanner.getStartPos() : end;
|
||||
node.flags |= contextFlags;
|
||||
|
||||
// Keep track on the node if we encountered an error while parsing it. If we did, then
|
||||
// we cannot reuse the node incrementally. Once we've marked this node, clear out the
|
||||
// flag so that we don't mark any subsequent nodes.
|
||||
if (parseErrorBeforeNextFinishedNode) {
|
||||
parseErrorBeforeNextFinishedNode = false;
|
||||
node.flags |= NodeFlags.ThisNodeHasError;
|
||||
}
|
||||
|
||||
node.flags &= ~NodeFlags.Synthesized;
|
||||
return node;
|
||||
}
|
||||
|
||||
function makeParseArray<T extends Node>(elements: T[], pos?: number, end?: number): NodeArray<T> {
|
||||
if (elements) {
|
||||
const array = <NodeArray<T>>elements;
|
||||
array.pos = pos === undefined ? getNodePos() : pos;
|
||||
array.end = end === undefined ? getNodeEnd() : end;
|
||||
return array;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseUntil<T extends Node>(parseNode: () => T, condition: (node: T) => boolean): NodeArray<T> {
|
||||
const fullStart = getNodePos();
|
||||
const elements: T[] = [];
|
||||
while (true) {
|
||||
const node = parseNode();
|
||||
elements.push(node);
|
||||
if (condition(node)) {
|
||||
return makeParseArray(elements, fullStart)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createMissingNode(kind: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node {
|
||||
if (reportAtCurrentPosition) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0);
|
||||
@ -1198,19 +1238,21 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseComputedPropertyName(): ComputedPropertyName {
|
||||
const fullStart = scanner.getStartPos();
|
||||
|
||||
// PropertyName [Yield]:
|
||||
// LiteralPropertyName
|
||||
// ComputedPropertyName[?Yield]
|
||||
const node = <ComputedPropertyName>createNode(SyntaxKind.ComputedPropertyName);
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
|
||||
// We parse any expression (including a comma expression). But the grammar
|
||||
// says that only an assignment expression is allowed, so the grammar checker
|
||||
// will error if it sees a comma expression.
|
||||
node.expression = allowInAnd(parseExpression);
|
||||
const expression = allowInAnd(parseExpression);
|
||||
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
return finishNode(node);
|
||||
|
||||
return makeParseNode(createComputedPropertyName(expression), fullStart);
|
||||
}
|
||||
|
||||
function parseContextualModifier(t: SyntaxKind): boolean {
|
||||
@ -1919,10 +1961,7 @@ namespace ts {
|
||||
function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
|
||||
let entity: EntityName = parseIdentifier(diagnosticMessage);
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos); // !!!
|
||||
node.left = entity;
|
||||
node.right = parseRightSideOfDot(allowReservedWords);
|
||||
entity = finishNode(node);
|
||||
entity = makeParseNode(createQualifiedName(entity, parseRightSideOfDot(allowReservedWords)), entity.pos);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
@ -1962,39 +2001,22 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTemplateExpression(): TemplateExpression {
|
||||
const template = <TemplateExpression>createNode(SyntaxKind.TemplateExpression);
|
||||
|
||||
template.head = parseTemplateHead();
|
||||
Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
|
||||
|
||||
const templateSpans = createNodeArray<TemplateSpan>();
|
||||
|
||||
do {
|
||||
templateSpans.push(parseTemplateSpan());
|
||||
}
|
||||
while (lastOrUndefined(templateSpans).literal.kind === SyntaxKind.TemplateMiddle);
|
||||
|
||||
templateSpans.end = getNodeEnd();
|
||||
template.templateSpans = templateSpans;
|
||||
|
||||
return finishNode(template);
|
||||
const fullStart = getNodePos();
|
||||
return makeParseNode(
|
||||
createTemplateExpression(
|
||||
parseTemplateHead(),
|
||||
parseUntil(parseTemplateSpan, span => span.literal.kind !== SyntaxKind.TemplateMiddle)
|
||||
), fullStart);
|
||||
}
|
||||
|
||||
function parseTemplateSpan(): TemplateSpan {
|
||||
const span = <TemplateSpan>createNode(SyntaxKind.TemplateSpan);
|
||||
span.expression = allowInAnd(parseExpression);
|
||||
|
||||
let literal: TemplateMiddle | TemplateTail;
|
||||
if (token() === SyntaxKind.CloseBraceToken) {
|
||||
reScanTemplateToken();
|
||||
literal = parseTemplateMiddleOrTemplateTail();
|
||||
}
|
||||
else {
|
||||
literal = <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
|
||||
}
|
||||
|
||||
span.literal = literal;
|
||||
return finishNode(span);
|
||||
const fullStart = getNodePos();
|
||||
return makeParseNode(
|
||||
createTemplateSpan(
|
||||
allowInAnd(parseExpression),
|
||||
parseTemplateMiddleOrTemplateTail()
|
||||
),
|
||||
fullStart);
|
||||
}
|
||||
|
||||
function parseLiteralNode(internName?: boolean): LiteralExpression {
|
||||
@ -2008,9 +2030,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail {
|
||||
const fragment = parseLiteralLikeNode(token(), /*internName*/ false);
|
||||
Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");
|
||||
return <TemplateMiddle | TemplateTail>fragment;
|
||||
if (token() === SyntaxKind.CloseBraceToken) {
|
||||
reScanTemplateToken();
|
||||
const fragment = parseLiteralLikeNode(token(), /*internName*/ false);
|
||||
Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");
|
||||
return <TemplateMiddle | TemplateTail>fragment;
|
||||
}
|
||||
return <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
|
||||
}
|
||||
|
||||
function parseLiteralLikeNode(kind: SyntaxKind, internName: boolean): LiteralLikeNode {
|
||||
@ -2049,21 +2075,28 @@ namespace ts {
|
||||
// TYPES
|
||||
|
||||
function parseTypeReference(): TypeReferenceNode {
|
||||
const typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected);
|
||||
const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference, typeName.pos);
|
||||
node.typeName = typeName;
|
||||
if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken) {
|
||||
node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
return finishNode(node);
|
||||
const fullStart = getNodePos();
|
||||
return makeParseNode(
|
||||
createTypeReference(
|
||||
parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected),
|
||||
tryParseTypeArguments()
|
||||
), fullStart);
|
||||
}
|
||||
|
||||
function tryParseTypeArguments() {
|
||||
return !scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken
|
||||
? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {
|
||||
nextToken();
|
||||
const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode;
|
||||
node.parameterName = lhs;
|
||||
node.type = parseType();
|
||||
return finishNode(node);
|
||||
return makeParseNode(
|
||||
createTypePredicate(
|
||||
lhs,
|
||||
parseType()
|
||||
),
|
||||
lhs.pos);
|
||||
}
|
||||
|
||||
function parseThisTypeNode(): ThisTypeNode {
|
||||
@ -2073,36 +2106,43 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTypeQuery(): TypeQueryNode {
|
||||
const node = <TypeQueryNode>createNode(SyntaxKind.TypeQuery);
|
||||
const fullStart = getNodePos();
|
||||
parseExpected(SyntaxKind.TypeOfKeyword);
|
||||
node.exprName = parseEntityName(/*allowReservedWords*/ true);
|
||||
return finishNode(node);
|
||||
return makeParseNode(
|
||||
createTypeQuery(
|
||||
parseEntityName(/*allowReservedWords*/ true)
|
||||
),
|
||||
fullStart);
|
||||
}
|
||||
|
||||
function parseTypeParameter(): TypeParameterDeclaration {
|
||||
const node = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
|
||||
node.name = parseIdentifier();
|
||||
const fullStart = getNodePos();
|
||||
return makeParseNode(
|
||||
createTypeParameter(
|
||||
parseIdentifier(),
|
||||
parseTypeParameterConstraint()
|
||||
),
|
||||
fullStart);
|
||||
}
|
||||
|
||||
function parseTypeParameterConstraint() {
|
||||
if (parseOptional(SyntaxKind.ExtendsKeyword)) {
|
||||
// It's not uncommon for people to write improper constraints to a generic. If the
|
||||
// user writes a constraint that is an expression and not an actual type, then parse
|
||||
// it out as an expression (so we can recover well), but report that a type is needed
|
||||
// instead.
|
||||
if (isStartOfType() || !isStartOfExpression()) {
|
||||
node.constraint = parseType();
|
||||
}
|
||||
else {
|
||||
// It was not a type, and it looked like an expression. Parse out an expression
|
||||
// here so we recover well. Note: it is important that we call parseUnaryExpression
|
||||
// and not parseExpression here. If the user has:
|
||||
//
|
||||
// <T extends "">
|
||||
//
|
||||
// We do *not* want to consume the > as we're consuming the expression for "".
|
||||
node.expression = parseUnaryExpressionOrHigher();
|
||||
return parseType();
|
||||
}
|
||||
// It was not a type, and it looked like an expression. Parse out an expression
|
||||
// here so we recover well. Note: it is important that we call parseUnaryExpression
|
||||
// and not parseExpression here. If the user has:
|
||||
//
|
||||
// <T extends "">
|
||||
//
|
||||
// We do *not* want to consume the > as we're consuming the expression for "".
|
||||
return parseUnaryExpressionOrHigher();
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseTypeParameters(): NodeArray<TypeParameterDeclaration> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user