Optimize finishNode calls in parser

Spreading the 3 finishing values turns out to be noticeably cheaper
than spreading the unfinished node.
This commit is contained in:
Nick Guerrera 2021-04-25 15:10:20 -07:00
Родитель 3ac9719b17
Коммит fa575e515e
1 изменённых файлов: 150 добавлений и 210 удалений

Просмотреть файл

@ -186,7 +186,7 @@ export function parse(code: string | SourceFile) {
locals: createSymbolTable(),
inScopeNamespaces: [],
parseDiagnostics,
...finishNode({}, 0),
...finishNode(0),
};
}
@ -316,8 +316,6 @@ export function parse(code: string | SourceFile) {
}
nsSegments.push(currentName);
let parameters: ModelExpressionNode | undefined;
const nextTok = parseExpectedOneOf(Token.Semicolon, Token.OpenBrace);
let statements: Statement[] | undefined;
@ -326,28 +324,22 @@ export function parse(code: string | SourceFile) {
parseExpected(Token.CloseBrace);
}
let outerNs: NamespaceStatementNode = finishNode(
{
kind: SyntaxKind.NamespaceStatement,
decorators,
name: nsSegments[0],
parameters,
statements,
},
nsSegments[0].pos
);
let outerNs: NamespaceStatementNode = {
kind: SyntaxKind.NamespaceStatement,
decorators,
name: nsSegments[0],
statements,
...finishNode(nsSegments[0].pos),
};
for (let i = 1; i < nsSegments.length; i++) {
outerNs = finishNode(
{
kind: SyntaxKind.NamespaceStatement,
decorators: [],
name: nsSegments[i],
parameters,
statements: outerNs,
},
nsSegments[i].pos
);
outerNs = {
kind: SyntaxKind.NamespaceStatement,
decorators: [],
name: nsSegments[i],
statements: outerNs,
...finishNode(nsSegments[i].pos),
};
}
return outerNs;
@ -359,13 +351,11 @@ export function parse(code: string | SourceFile) {
const name = parseIdentifierOrMemberExpression();
parseExpected(Token.Semicolon);
return finishNode(
{
kind: SyntaxKind.UsingStatement,
name,
},
pos
);
return {
kind: SyntaxKind.UsingStatement,
name,
...finishNode(pos),
};
}
function parseOperationStatement(decorators: DecoratorExpressionNode[]): OperationStatementNode {
@ -379,28 +369,24 @@ export function parse(code: string | SourceFile) {
const returnType = parseExpression();
parseExpected(Token.Semicolon);
return finishNode(
{
kind: SyntaxKind.OperationStatement,
id,
parameters,
returnType,
decorators,
},
pos
);
return {
kind: SyntaxKind.OperationStatement,
id,
parameters,
returnType,
decorators,
...finishNode(pos),
};
}
function parseOperationParameters(): ModelExpressionNode {
const pos = tokenPos();
const properties = parseList(ListKind.OperationParameters, parseModelPropertyOrSpread);
const parameters: ModelExpressionNode = finishNode(
{
kind: SyntaxKind.ModelExpression,
properties,
},
pos
);
const parameters: ModelExpressionNode = {
kind: SyntaxKind.ModelExpression,
properties,
...finishNode(pos),
};
return parameters;
}
@ -420,32 +406,28 @@ export function parse(code: string | SourceFile) {
const assignment = parseExpression();
parseExpected(Token.Semicolon);
return finishNode(
{
kind: SyntaxKind.ModelStatement,
id,
heritage: [],
templateParameters,
assignment,
decorators,
},
pos
);
return {
kind: SyntaxKind.ModelStatement,
id,
heritage: [],
templateParameters,
assignment,
decorators,
...finishNode(pos),
};
} else {
const heritage: ReferenceExpression[] = parseOptionalModelHeritage();
const properties = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
return finishNode(
{
kind: SyntaxKind.ModelStatement,
id,
heritage,
templateParameters,
decorators,
properties,
},
pos
);
return {
kind: SyntaxKind.ModelStatement,
id,
heritage,
templateParameters,
decorators,
properties,
...finishNode(pos),
};
}
}
@ -463,13 +445,11 @@ export function parse(code: string | SourceFile) {
): TemplateParameterDeclarationNode {
reportInvalidDecorators(decorators, "template parameter");
const id = parseIdentifier();
return finishNode(
{
kind: SyntaxKind.TemplateParameterDeclaration,
id,
},
pos
);
return {
kind: SyntaxKind.TemplateParameterDeclaration,
id,
...finishNode(pos),
};
}
function parseModelPropertyOrSpread(pos: number, decorators: DecoratorExpressionNode[]) {
@ -489,13 +469,11 @@ export function parse(code: string | SourceFile) {
// This could be broadened to allow any type expression
const target = parseReferenceExpression();
return finishNode(
{
kind: SyntaxKind.ModelSpreadProperty,
target,
},
pos
);
return {
kind: SyntaxKind.ModelSpreadProperty,
target,
...finishNode(pos),
};
}
function parseModelProperty(
@ -511,16 +489,14 @@ export function parse(code: string | SourceFile) {
parseExpected(Token.Colon);
const value = parseExpression();
return finishNode(
{
kind: SyntaxKind.ModelProperty,
id,
decorators,
value,
optional,
},
pos
);
return {
kind: SyntaxKind.ModelProperty,
id,
decorators,
value,
optional,
...finishNode(pos),
};
}
function parseExpression(): Expression {
@ -536,22 +512,17 @@ export function parse(code: string | SourceFile) {
return node;
}
node = finishNode(
{
kind: SyntaxKind.UnionExpression,
options: [node],
},
pos
);
const options = [node];
while (parseOptional(Token.Bar)) {
const expr = parseIntersectionExpressionOrHigher();
node.options.push(expr);
options.push(expr);
}
node.end = tokenPos();
return node;
return {
kind: SyntaxKind.UnionExpression,
options,
...finishNode(pos),
};
}
function parseIntersectionExpressionOrHigher(): Expression {
@ -563,22 +534,17 @@ export function parse(code: string | SourceFile) {
return node;
}
node = finishNode(
{
kind: SyntaxKind.IntersectionExpression,
options: [node],
},
pos
);
const options = [node];
while (parseOptional(Token.Ampersand)) {
const expr = parseArrayExpressionOrHigher();
node.options.push(expr);
options.push(expr);
}
node.end = tokenPos();
return node;
return {
kind: SyntaxKind.UnionExpression,
options,
...finishNode(pos),
};
}
function parseArrayExpressionOrHigher(): Expression {
@ -588,13 +554,11 @@ export function parse(code: string | SourceFile) {
while (parseOptional(Token.OpenBracket)) {
parseExpected(Token.CloseBracket);
expr = finishNode(
{
kind: SyntaxKind.ArrayExpression,
elementType: expr,
},
pos
);
expr = {
kind: SyntaxKind.ArrayExpression,
elementType: expr,
...finishNode(pos),
};
}
return expr;
@ -605,14 +569,12 @@ export function parse(code: string | SourceFile) {
const target = parseIdentifierOrMemberExpression();
const args = parseOptionalList(ListKind.TemplateArguments, parseExpression);
return finishNode(
{
kind: SyntaxKind.TypeReference,
target,
arguments: args,
},
pos
);
return {
kind: SyntaxKind.TypeReference,
target,
arguments: args,
...finishNode(pos),
};
}
function parseImportStatement(): ImportStatementNode {
@ -622,13 +584,11 @@ export function parse(code: string | SourceFile) {
const path = parseStringLiteral();
parseExpected(Token.Semicolon);
return finishNode(
{
kind: SyntaxKind.ImportStatement,
path,
},
pos
);
return {
kind: SyntaxKind.ImportStatement,
path,
...finishNode(pos),
};
}
function parseDecoratorExpression(): DecoratorExpressionNode {
@ -637,14 +597,12 @@ export function parse(code: string | SourceFile) {
const target = parseIdentifierOrMemberExpression();
const args = parseOptionalList(ListKind.DecoratorArguments, parseExpression);
return finishNode(
{
kind: SyntaxKind.DecoratorExpression,
arguments: args,
target,
},
pos
);
return {
kind: SyntaxKind.DecoratorExpression,
arguments: args,
target,
...finishNode(pos),
};
}
function parseIdentifierOrMemberExpression(): IdentifierNode | MemberExpressionNode {
@ -652,14 +610,12 @@ export function parse(code: string | SourceFile) {
while (parseOptional(Token.Dot)) {
const pos = tokenPos();
base = finishNode(
{
kind: SyntaxKind.MemberExpression,
base,
id: parseIdentifier(),
},
pos
);
base = {
kind: SyntaxKind.MemberExpression,
base,
id: parseIdentifier(),
...finishNode(pos),
};
}
return base;
@ -698,44 +654,38 @@ export function parse(code: string | SourceFile) {
parseExpected(Token.OpenParen);
const expr = parseExpression();
parseExpected(Token.CloseParen);
return finishNode(expr, pos);
return { ...expr, ...finishNode(pos) };
}
function parseTupleExpression(): TupleExpressionNode {
const pos = tokenPos();
const values = parseList(ListKind.Tuple, parseExpression);
return finishNode(
{
kind: SyntaxKind.TupleExpression,
values,
},
pos
);
return {
kind: SyntaxKind.TupleExpression,
values,
...finishNode(pos),
};
}
function parseModelExpression(): ModelExpressionNode {
const pos = tokenPos();
const properties = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
return finishNode(
{
kind: SyntaxKind.ModelExpression,
properties,
},
pos
);
return {
kind: SyntaxKind.ModelExpression,
properties,
...finishNode(pos),
};
}
function parseStringLiteral(): StringLiteralNode {
const pos = tokenPos();
const value = tokenValue();
parseExpected(Token.StringLiteral);
return finishNode(
{
kind: SyntaxKind.StringLiteral,
value,
},
pos
);
return {
kind: SyntaxKind.StringLiteral,
value,
...finishNode(pos),
};
}
function parseNumericLiteral(): NumericLiteralNode {
@ -744,27 +694,22 @@ export function parse(code: string | SourceFile) {
const value = Number(text);
parseExpected(Token.NumericLiteral);
return finishNode(
{
kind: SyntaxKind.NumericLiteral,
text,
value,
},
pos
);
return {
kind: SyntaxKind.NumericLiteral,
value,
...finishNode(pos),
};
}
function parseBooleanLiteral(): BooleanLiteralNode {
const pos = tokenPos();
const token = parseExpectedOneOf(Token.TrueKeyword, Token.FalseKeyword);
const value = token === Token.TrueKeyword;
return finishNode(
{
kind: SyntaxKind.BooleanLiteral,
value,
},
pos
);
return {
kind: SyntaxKind.BooleanLiteral,
value,
...finishNode(pos),
};
}
function parseIdentifier(message?: string): IdentifierNode {
@ -781,13 +726,11 @@ export function parse(code: string | SourceFile) {
const sv = tokenValue();
nextToken();
return finishNode(
{
kind: SyntaxKind.Identifier,
sv,
},
pos
);
return {
kind: SyntaxKind.Identifier,
sv,
...finishNode(pos),
};
}
// utility functions
@ -816,21 +759,18 @@ export function parse(code: string | SourceFile) {
function createMissingIdentifier(): IdentifierNode {
missingIdentifierCounter++;
return finishNode(
{
kind: SyntaxKind.Identifier,
sv: "<missing identifier>" + missingIdentifierCounter,
},
tokenPos()
);
return {
kind: SyntaxKind.Identifier,
sv: "<missing identifier>" + missingIdentifierCounter,
...finishNode(tokenPos()),
};
}
function finishNode<T>(o: T, pos: number): T & TextRange & { flags: NodeFlags } {
function finishNode(pos: number): TextRange & { flags: NodeFlags } {
const flags = parseErrorInNextFinishedNode ? NodeFlags.ThisNodeHasError : NodeFlags.None;
parseErrorInNextFinishedNode = false;
return {
...o,
pos,
end: previousTokenEnd,
flags,
@ -953,7 +893,7 @@ export function parse(code: string | SourceFile) {
function parseEmptyStatement(): EmptyStatementNode {
const pos = tokenPos();
parseExpected(Token.Semicolon);
return finishNode({ kind: SyntaxKind.EmptyStatement }, pos);
return { kind: SyntaxKind.EmptyStatement, ...finishNode(pos) };
}
function parseInvalidStatement(): InvalidStatementNode {
@ -972,7 +912,7 @@ export function parse(code: string | SourceFile) {
);
error("Statement expected.", { pos, end: previousTokenEnd });
return finishNode({ kind: SyntaxKind.InvalidStatement }, pos);
return { kind: SyntaxKind.InvalidStatement, ...finishNode(pos) };
}
function error(message: string, target?: TextRange & { realPos?: number }) {