Implement function types / indirect calls / trampolines (#39)

This commit is contained in:
Daniel Wirtz
2018-03-12 14:06:39 +01:00
committed by GitHub
parent 5d5f458ab1
commit 423533c6b0
67 changed files with 7499 additions and 5763 deletions

View File

@ -25,6 +25,8 @@ export enum NodeKind {
// types
TYPE,
TYPEPARAMETER,
PARAMETER,
SIGNATURE,
// expressions
IDENTIFIER,
@ -82,11 +84,10 @@ export enum NodeKind {
TYPEDECLARATION,
VARIABLEDECLARATION,
// other
// special
DECORATOR,
EXPORTMEMBER,
MODIFIER,
PARAMETER,
EXPORTMEMBER,
SWITCHCASE
}
@ -103,19 +104,121 @@ export abstract class Node {
// types
static createType(
identifier: IdentifierExpression,
typeArguments: TypeNode[],
name: IdentifierExpression,
typeArguments: CommonTypeNode[] | null,
isNullable: bool,
range: Range
): TypeNode {
var type = new TypeNode();
type.range = range;
type.name = identifier;
type.typeArguments = typeArguments;
type.name = name; name.parent = type;
type.typeArguments = typeArguments; if (typeArguments) setParent(typeArguments, type);
type.isNullable = isNullable;
return type;
}
static createOmittedType(
range: Range
) {
return Node.createType(
Node.createIdentifierExpression("", range),
null,
false,
range
);
}
static createTypeParameter(
name: IdentifierExpression,
extendsType: TypeNode | null,
range: Range
): TypeParameterNode {
var elem = new TypeParameterNode();
elem.range = range;
elem.name = name; name.parent = elem;
elem.extendsType = extendsType; if (extendsType) extendsType.parent = elem;
return elem;
}
static createParameter(
name: IdentifierExpression,
type: CommonTypeNode | null,
initializer: Expression | null,
kind: ParameterKind,
range: Range
): ParameterNode {
var elem = new ParameterNode();
elem.range = range;
elem.name = name; name.parent = elem;
elem.type = type; if (type) type.parent = elem;
elem.initializer = initializer; if (initializer) initializer.parent = elem;
elem.parameterKind = kind;
return elem;
}
static createSignature(
parameters: ParameterNode[],
returnType: CommonTypeNode,
explicitThisType: TypeNode | null,
isNullable: bool,
range: Range
): SignatureNode {
var sig = new SignatureNode();
sig.range = range;
sig.parameterTypes = parameters; setParent(parameters, sig);
sig.returnType = returnType; returnType.parent = sig;
sig.explicitThisType = explicitThisType; if (explicitThisType) explicitThisType.parent = sig;
sig.isNullable = isNullable;
return sig;
}
// special
static createDecorator(
expression: Expression,
args: Expression[] | null,
range: Range
): DecoratorNode {
var stmt = new DecoratorNode();
stmt.range = range;
stmt.name = expression; expression.parent = stmt;
stmt.arguments = args; if (args) setParent(args, stmt);
if (expression.kind == NodeKind.IDENTIFIER) {
switch ((<IdentifierExpression>expression).text) {
case "global": {
stmt.decoratorKind = DecoratorKind.GLOBAL;
break;
}
case "operator": {
stmt.decoratorKind = DecoratorKind.OPERATOR;
break;
}
case "unmanaged": {
stmt.decoratorKind = DecoratorKind.UNMANAGED;
break;
}
case "offset": {
stmt.decoratorKind = DecoratorKind.OFFSET;
break;
}
default: {
stmt.decoratorKind = DecoratorKind.CUSTOM;
break;
}
}
} else {
stmt.decoratorKind = DecoratorKind.CUSTOM;
}
return stmt;
}
static createModifier(kind: ModifierKind, range: Range): ModifierNode {
var elem = new ModifierNode();
elem.range = range;
elem.modifierKind = kind;
return elem;
}
// expressions
static createIdentifierExpression(
@ -128,20 +231,29 @@ export abstract class Node {
return expr;
}
static createEmptyIdentifierExpression(
range: Range
): IdentifierExpression {
var expr = new IdentifierExpression();
expr.range = range;
expr.text = "";
return expr;
}
static createArrayLiteralExpression(
elements: (Expression | null)[],
range: Range
): ArrayLiteralExpression {
var expr = new ArrayLiteralExpression();
expr.range = range;
expr.elementExpressions = elements; setParentOpt(elements, expr);
expr.elementExpressions = elements; setParentIfNotNull(elements, expr);
return expr;
}
static createAssertionExpression(
assertionKind: AssertionKind,
expression: Expression,
toType: TypeNode,
toType: CommonTypeNode,
range: Range
): AssertionExpression {
var expr = new AssertionExpression();
@ -168,7 +280,7 @@ export abstract class Node {
static createCallExpression(
expression: Expression,
typeArgs: TypeNode[] | null,
typeArgs: CommonTypeNode[] | null,
args: Expression[],
range: Range
): CallExpression {
@ -252,7 +364,7 @@ export abstract class Node {
static createNewExpression(
expression: Expression,
typeArgs: TypeNode[] | null,
typeArgs: CommonTypeNode[] | null,
args: Expression[],
range: Range
): NewExpression {
@ -402,12 +514,12 @@ export abstract class Node {
static createClassDeclaration(
identifier: IdentifierExpression,
typeParameters: TypeParameter[],
extendsType: TypeNode | null,
implementsTypes: TypeNode[],
typeParameters: TypeParameterNode[],
extendsType: TypeNode | null, // can't be a function
implementsTypes: TypeNode[], // can't be a function
members: DeclarationStatement[],
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): ClassDeclaration {
var stmt = new ClassDeclaration();
@ -432,29 +544,6 @@ export abstract class Node {
return stmt;
}
static createDecorator(
expression: Expression,
args: Expression[] | null,
range: Range
): Decorator {
var stmt = new Decorator();
stmt.range = range;
stmt.name = expression; expression.parent = stmt;
stmt.arguments = args; if (args) setParent(args, stmt);
if (expression.kind == NodeKind.IDENTIFIER) {
switch ((<IdentifierExpression>expression).text) {
case "global": stmt.decoratorKind = DecoratorKind.GLOBAL; break;
case "operator": stmt.decoratorKind = DecoratorKind.OPERATOR; break;
case "unmanaged": stmt.decoratorKind = DecoratorKind.UNMANAGED; break;
case "offset": stmt.decoratorKind = DecoratorKind.OFFSET; break;
default: stmt.decoratorKind = DecoratorKind.CUSTOM; break;
}
} else {
stmt.decoratorKind = DecoratorKind.CUSTOM;
}
return stmt;
}
static createDoStatement(
statement: Statement,
condition: Expression,
@ -478,8 +567,8 @@ export abstract class Node {
static createEnumDeclaration(
name: IdentifierExpression,
members: EnumValueDeclaration[],
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): EnumDeclaration {
var stmt = new EnumDeclaration();
@ -506,7 +595,7 @@ export abstract class Node {
static createExportStatement(
members: ExportMember[],
path: StringLiteralExpression | null,
modifiers: Modifier[] | null,
modifiers: ModifierNode[] | null,
range: Range
): ExportStatement {
var stmt = new ExportStatement();
@ -644,9 +733,9 @@ export abstract class Node {
static createInterfaceDeclaration(
name: IdentifierExpression,
extendsType: TypeNode | null,
extendsType: TypeNode | null, // can't be a function
members: DeclarationStatement[],
modifiers: Modifier[] | null,
modifiers: ModifierNode[] | null,
range: Range
): InterfaceDeclaration {
var stmt = new InterfaceDeclaration();
@ -660,10 +749,10 @@ export abstract class Node {
static createFieldDeclaration(
name: IdentifierExpression,
type: TypeNode | null,
type: CommonTypeNode | null,
initializer: Expression | null,
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): FieldDeclaration {
var stmt = new FieldDeclaration();
@ -692,50 +781,20 @@ export abstract class Node {
return stmt;
}
static createTypeParameter(
name: IdentifierExpression,
extendsType: TypeNode | null,
range: Range
): TypeParameter {
var elem = new TypeParameter();
elem.range = range;
elem.name = name; name.parent = elem;
elem.extendsType = extendsType; if (extendsType) extendsType.parent = elem;
return elem;
}
static createParameter(
name: IdentifierExpression,
type: TypeNode | null,
initializer: Expression | null,
kind: ParameterKind,
range: Range
): Parameter {
var elem = new Parameter();
elem.range = range;
elem.name = name; name.parent = elem;
elem.type = type; if (type) type.parent = elem;
elem.initializer = initializer; if (initializer) initializer.parent = elem;
elem.parameterKind = kind;
return elem;
}
static createFunctionDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameter[] | null,
parameters: Parameter[],
returnType: TypeNode | null,
typeParameters: TypeParameterNode[] | null,
signature: SignatureNode,
body: Statement | null,
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): FunctionDeclaration {
var stmt = new FunctionDeclaration();
stmt.range = range;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.parameters = parameters; setParent(parameters, stmt);
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
stmt.signature = signature; signature.parent = stmt;
stmt.body = body; if (body) body.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
@ -744,38 +803,29 @@ export abstract class Node {
static createMethodDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameter[] | null,
parameters: Parameter[],
returnType: TypeNode | null,
typeParameters: TypeParameterNode[] | null,
signature: SignatureNode,
body: Statement | null,
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): MethodDeclaration {
var stmt = new MethodDeclaration();
stmt.range = range;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.parameters = parameters; setParent(parameters, stmt);
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
stmt.signature = signature; signature.parent = stmt;
stmt.body = body; if (body) body.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt;
}
static createModifier(kind: ModifierKind, range: Range): Modifier {
var elem = new Modifier();
elem.range = range;
elem.modifierKind = kind;
return elem;
}
static createNamespaceDeclaration(
name: IdentifierExpression,
members: Statement[],
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): NamespaceDeclaration {
var stmt = new NamespaceDeclaration();
@ -852,9 +902,9 @@ export abstract class Node {
static createTypeDeclaration(
name: IdentifierExpression,
alias: TypeNode,
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
alias: CommonTypeNode,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): TypeDeclaration {
var stmt = new TypeDeclaration();
@ -868,8 +918,8 @@ export abstract class Node {
static createVariableStatement(
declarations: VariableDeclaration[],
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): VariableStatement {
var stmt = new VariableStatement();
@ -882,10 +932,10 @@ export abstract class Node {
static createVariableDeclaration(
name: IdentifierExpression,
type: TypeNode | null,
type: CommonTypeNode | null,
initializer: Expression | null,
modifiers: Modifier[] | null,
decorators: Decorator[] | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null,
range: Range
): VariableDeclaration {
var elem = new VariableDeclaration();
@ -923,26 +973,116 @@ export abstract class Node {
// types
export abstract class CommonTypeNode extends Node {
// kind varies
/** Whether nullable or not. */
isNullable: bool;
}
/** Represents a type annotation. */
export class TypeNode extends Node {
export class TypeNode extends CommonTypeNode {
kind = NodeKind.TYPE;
/** Identifier reference. */
name: IdentifierExpression;
/** Type argument references. */
typeArguments: TypeNode[];
/** Whether nullable or not. */
isNullable: bool;
typeArguments: CommonTypeNode[] | null;
}
/** Represents a type parameter. */
export class TypeParameter extends Node {
export class TypeParameterNode extends Node {
kind = NodeKind.TYPEPARAMETER;
/** Identifier reference. */
name: IdentifierExpression;
/** Extended type reference, if any. */
extendsType: TypeNode | null;
extendsType: TypeNode | null; // can't be a function
}
/** Represents the kind of a parameter. */
export enum ParameterKind {
/** No specific flags. */
DEFAULT,
/** Is an optional parameter. */
OPTIONAL,
/** Is a rest parameter. */
REST
}
/** Represents a function parameter. */
export class ParameterNode extends Node {
kind = NodeKind.PARAMETER;
/** Parameter kind. */
parameterKind: ParameterKind;
/** Parameter name. */
name: IdentifierExpression;
/** Parameter type. */
type: CommonTypeNode | null;
/** Initializer expression, if present. */
initializer: Expression | null;
}
/** Represents a function signature. */
export class SignatureNode extends CommonTypeNode {
kind = NodeKind.SIGNATURE;
/** Accepted parameters. */
parameterTypes: ParameterNode[];
/** Return type. */
returnType: CommonTypeNode | null;
/** Explicitly provided this type, if any. */
explicitThisType: TypeNode | null; // can't be a function
}
// special
/** Built-in decorator kinds. */
export const enum DecoratorKind {
CUSTOM,
GLOBAL,
OPERATOR,
UNMANAGED,
OFFSET
}
/** Depresents a decorator. */
export class DecoratorNode extends Node {
kind = NodeKind.DECORATOR;
/** Built-in kind, if applicable. */
decoratorKind: DecoratorKind;
/** Name expression. */
name: Expression;
/** Argument expressions. */
arguments: Expression[] | null;
}
/** Indicates the specific kind of a modifier. */
export enum ModifierKind {
ASYNC,
CONST,
LET,
DECLARE,
EXPORT,
IMPORT,
STATIC,
ABSTRACT,
PUBLIC,
PRIVATE,
PROTECTED,
READONLY,
GET,
SET,
}
/** Represents a single modifier. */
export class ModifierNode extends Node {
kind = NodeKind.MODIFIER;
/** Specific modifier kind. */
modifierKind: ModifierKind;
}
// expressions
@ -999,7 +1139,7 @@ export class AssertionExpression extends Expression {
/** Expression being asserted. */
expression: Expression;
/** Target type. */
toType: TypeNode;
toType: CommonTypeNode;
}
/** Represents a binary expression. */
@ -1021,7 +1161,7 @@ export class CallExpression extends Expression {
/** Called expression. Usually an identifier or property access expression. */
expression: Expression;
/** Provided type arguments. */
typeArguments: TypeNode[] | null;
typeArguments: CommonTypeNode[] | null;
/** Provided arguments. */
arguments: Expression[];
}
@ -1183,24 +1323,6 @@ export class UnaryPrefixExpression extends UnaryExpression {
// statements
/** Indicates the specific kind of a modifier. */
export enum ModifierKind {
ASYNC,
CONST,
LET,
DECLARE,
EXPORT,
IMPORT,
STATIC,
ABSTRACT,
PUBLIC,
PRIVATE,
PROTECTED,
READONLY,
GET,
SET,
}
/** Base class of all statement nodes. */
export abstract class Statement extends Node { }
@ -1257,9 +1379,9 @@ export abstract class DeclarationStatement extends Statement {
/** Simple name being declared. */
name: IdentifierExpression;
/** Array of modifiers. */
modifiers: Modifier[] | null;
modifiers: ModifierNode[] | null;
/** Array of decorators. */
decorators: Decorator[] | null = null;
decorators: DecoratorNode[] | null = null;
protected cachedProgramLevelInternalName: string | null = null;
protected cachedFileLevelInternalName: string | null = null;
@ -1333,7 +1455,7 @@ export abstract class DeclarationStatement extends Statement {
export abstract class VariableLikeDeclarationStatement extends DeclarationStatement {
/** Variable type. */
type: TypeNode | null;
type: CommonTypeNode | null;
/** Variable initializer. */
initializer: Expression | null;
}
@ -1359,13 +1481,18 @@ export class ClassDeclaration extends DeclarationStatement {
kind = NodeKind.CLASSDECLARATION;
/** Accepted type parameters. */
typeParameters: TypeParameter[];
typeParameters: TypeParameterNode[];
/** Base class type being extended. */
extendsType: TypeNode | null;
extendsType: TypeNode | null; // can't be a function
/** Interface types being implemented. */
implementsTypes: TypeNode[];
implementsTypes: TypeNode[]; // can't be a function
/** Class member declarations. */
members: DeclarationStatement[];
get isGeneric(): bool {
var typeParameters = this.typeParameters;
return typeParameters != null && typeParameters.length > 0;
}
}
/** Represents a `continue` statement. */
@ -1376,27 +1503,6 @@ export class ContinueStatement extends Statement {
label: IdentifierExpression | null;
}
/** Built-in decorator kinds. */
export const enum DecoratorKind {
CUSTOM,
GLOBAL,
OPERATOR,
UNMANAGED,
OFFSET
}
/** Depresents a decorator. */
export class Decorator extends Statement {
kind = NodeKind.DECORATOR;
/** Name expression. */
name: Expression;
/** Argument expressions. */
arguments: Expression[] | null;
/** Built-in kind, if applicable. */
decoratorKind: DecoratorKind;
}
/** Represents a `do` statement. */
export class DoStatement extends Statement {
kind = NodeKind.DO;
@ -1455,7 +1561,7 @@ export class ExportStatement extends Statement {
kind = NodeKind.EXPORT;
/** Array of modifiers. */
modifiers: Modifier[] | null;
modifiers: ModifierNode[] | null;
/** Array of members. */
members: ExportMember[];
/** Path being exported from, if applicable. */
@ -1500,17 +1606,16 @@ export class ForStatement extends Statement {
export class FunctionDeclaration extends DeclarationStatement {
kind = NodeKind.FUNCTIONDECLARATION;
/** Accepted type parameters. */
typeParameters: TypeParameter[] | null;
/** Accepted parameters. */
parameters: Parameter[];
/** Return type. */
returnType: TypeNode | null;
/** Type parameters, if any. */
typeParameters: TypeParameterNode[] | null;
/** Function signature. */
signature: SignatureNode;
/** Body statement. Usually a block. */
body: Statement | null;
get isGeneric(): bool {
return this.typeParameters != null && this.typeParameters.length > 0;
var typeParameters = this.typeParameters;
return typeParameters != null && typeParameters.length > 0;
}
}
@ -1569,38 +1674,6 @@ export class NamespaceDeclaration extends DeclarationStatement {
members: Statement[];
}
/** Represents the kind of a parameter. */
export enum ParameterKind {
/** No specific flags. */
DEFAULT,
/** Is an optional parameter. */
OPTIONAL,
/** Is a rest parameter. */
REST
}
/** Represents a function parameter. */
export class Parameter extends Node {
kind = NodeKind.PARAMETER;
/** Parameter name. */
name: IdentifierExpression;
/** Parameter type. */
type: TypeNode | null;
/** Parameter kind. */
parameterKind: ParameterKind;
/** Initializer expression, if present. */
initializer: Expression | null;
}
/** Represents a single modifier. */
export class Modifier extends Node {
kind = NodeKind.MODIFIER;
/** Specific modifier kind. */
modifierKind: ModifierKind;
}
/** Represents a `return` statement. */
export class ReturnStatement extends Statement {
kind = NodeKind.RETURN;
@ -1656,7 +1729,7 @@ export class TypeDeclaration extends DeclarationStatement {
kind = NodeKind.TYPEDECLARATION;
/** Type being aliased. */
alias: TypeNode;
alias: CommonTypeNode;
}
/** Represents a variable declaration part of a {@link VariableStatement}. */
@ -1664,7 +1737,7 @@ export class VariableDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.VARIABLEDECLARATION;
/** Array of modifiers. */
modifiers: Modifier[] | null;
modifiers: ModifierNode[] | null;
}
/** Represents a variable statement wrapping {@link VariableDeclaration}s. */
@ -1672,9 +1745,9 @@ export class VariableStatement extends Statement {
kind = NodeKind.VARIABLE;
/** Array of modifiers. */
modifiers: Modifier[] | null;
modifiers: ModifierNode[] | null;
/** Array of decorators. */
decorators: Decorator[] | null;
decorators: DecoratorNode[] | null;
/** Array of member declarations. */
declarations: VariableDeclaration[];
}
@ -1698,15 +1771,15 @@ export class WhileStatement extends Statement {
}
/** Cached unused modifiers for reuse. */
var reusableModifiers: Modifier[] | null = null;
var reusableModifiers: ModifierNode[] | null = null;
export function setReusableModifiers(modifiers: Modifier[]): void {
export function setReusableModifiers(modifiers: ModifierNode[]): void {
reusableModifiers = modifiers;
}
/** Creates a new modifiers array. */
export function createModifiers(): Modifier[] {
var ret: Modifier[];
export function createModifiers(): ModifierNode[] {
var ret: ModifierNode[];
if (reusableModifiers != null) {
ret = reusableModifiers;
reusableModifiers = null;
@ -1720,14 +1793,14 @@ export function createModifiers(): Modifier[] {
// Utility
/** Adds a modifier to a set of modifiers. Creates a new set if `null`. */
export function addModifier(modifier: Modifier, modifiers: Modifier[] | null): Modifier[] {
export function addModifier(modifier: ModifierNode, modifiers: ModifierNode[] | null): ModifierNode[] {
if (modifiers == null) modifiers = createModifiers();
modifiers.push(modifier);
return modifiers;
}
/** Gets a specific modifier from the specified set of modifiers. */
export function getModifier(kind: ModifierKind, modifiers: Modifier[] | null): Modifier | null {
export function getModifier(kind: ModifierKind, modifiers: ModifierNode[] | null): ModifierNode | null {
if (modifiers) {
for (var i = 0, k = modifiers.length; i < k; ++i) {
if (modifiers[i].modifierKind == kind) {
@ -1739,12 +1812,12 @@ export function getModifier(kind: ModifierKind, modifiers: Modifier[] | null): M
}
/** Tests whether a modifier exists in the specified set of modifiers. */
export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): bool {
export function hasModifier(kind: ModifierKind, modifiers: ModifierNode[] | null): bool {
return getModifier(kind, modifiers) != null;
}
/** Gets the first decorator by name within at set of decorators, if present. */
export function getFirstDecorator(name: string, decorators: Decorator[] | null): Decorator | null {
export function getFirstDecorator(name: string, decorators: DecoratorNode[] | null): DecoratorNode | null {
if (decorators) {
for (var i = 0, k = decorators.length; i < k; ++i) {
var decorator = decorators[i];
@ -1758,7 +1831,7 @@ export function getFirstDecorator(name: string, decorators: Decorator[] | null):
}
/** Tests if a specific decorator is present within the specified decorators. */
export function hasDecorator(name: string, decorators: Decorator[] | null): bool {
export function hasDecorator(name: string, decorators: DecoratorNode[] | null): bool {
return getFirstDecorator(name, decorators) != null;
}
@ -1800,13 +1873,15 @@ export function mangleInternalPath(path: string): string {
// Helpers
/** Sets the parent node on an array of nodes. */
function setParent(nodes: Node[], parent: Node): void {
for (var i = 0, k = nodes.length; i < k; ++i) {
nodes[i].parent = parent;
}
}
function setParentOpt(nodes: (Node | null)[], parent: Node): void {
/** Sets the parent node on an array of nullable nodes. */
function setParentIfNotNull(nodes: (Node | null)[], parent: Node): void {
for (var i = 0, k = nodes.length; i < k; ++i) {
var node = nodes[i];
if (node) node.parent = parent;