1850 lines
49 KiB
TypeScript
Raw Normal View History

2018-03-17 23:41:48 +01:00
/**
2018-03-19 01:12:18 +01:00
* Abstract syntax tree representing a source file once parsed.
* @module ast
*//***/
2018-03-17 23:41:48 +01:00
2017-12-24 03:19:47 +01:00
import {
CommonFlags,
2017-12-24 03:19:47 +01:00
PATH_DELIMITER,
STATIC_DELIMITER,
INSTANCE_DELIMITER,
LIBRARY_PREFIX
} from "./program";
2017-12-24 03:19:47 +01:00
import {
Token,
Tokenizer,
Range
} from "./tokenizer";
import {
2018-03-19 01:12:18 +01:00
normalizePath,
resolvePath,
CharCode
2018-03-19 01:12:18 +01:00
} from "./util";
2017-09-28 13:08:25 +02:00
export { Token, Range };
2017-09-28 13:08:25 +02:00
2017-12-16 17:54:53 +01:00
/** Indicates the kind of a node. */
2017-09-28 13:08:25 +02:00
export enum NodeKind {
SOURCE,
// types
TYPE,
TYPEPARAMETER,
PARAMETER,
SIGNATURE,
2017-09-28 13:08:25 +02:00
// expressions
IDENTIFIER,
ASSERTION,
BINARY,
CALL,
2018-01-05 01:55:59 +01:00
COMMA,
2017-09-28 13:08:25 +02:00
ELEMENTACCESS,
2017-10-07 14:29:43 +02:00
FALSE,
2018-02-27 00:30:04 +01:00
FUNCTION,
2017-09-28 13:08:25 +02:00
LITERAL,
NEW,
2017-10-07 14:29:43 +02:00
NULL,
2017-09-28 13:08:25 +02:00
PARENTHESIZED,
PROPERTYACCESS,
TERNARY,
2017-10-07 14:29:43 +02:00
SUPER,
THIS,
TRUE,
2017-12-16 02:27:39 +01:00
CONSTRUCTOR,
2017-09-28 13:08:25 +02:00
UNARYPOSTFIX,
UNARYPREFIX,
// statements
BLOCK,
BREAK,
CONTINUE,
DO,
EMPTY,
EXPORT,
EXPORTIMPORT,
EXPRESSION,
FOR,
IF,
IMPORT,
2017-09-28 13:08:25 +02:00
RETURN,
SWITCH,
THROW,
TRY,
VARIABLE,
VOID,
WHILE,
// declaration statements
CLASSDECLARATION,
ENUMDECLARATION,
ENUMVALUEDECLARATION,
FIELDDECLARATION,
FUNCTIONDECLARATION,
IMPORTDECLARATION,
INTERFACEDECLARATION,
METHODDECLARATION,
NAMESPACEDECLARATION,
TYPEDECLARATION,
2017-09-28 13:08:25 +02:00
VARIABLEDECLARATION,
2017-12-18 03:46:36 +01:00
// special
2017-12-18 03:46:36 +01:00
DECORATOR,
EXPORTMEMBER,
SWITCHCASE,
COMMENT
2017-09-28 13:08:25 +02:00
}
2017-12-16 17:54:53 +01:00
/** Base class of all nodes. */
export abstract class Node {
2017-09-28 13:08:25 +02:00
2017-12-16 17:54:53 +01:00
/** Node kind indicator. */
kind: NodeKind;
/** Source range. */
range: Range;
/** Parent node. */
parent: Node | null = null;
/** Common flags indicating specific traits. */
flags: CommonFlags = CommonFlags.NONE;
/** Tests if this node has the specified flag or flags. */
is(flag: CommonFlags): bool { return (this.flags & flag) == flag; }
/** Tests if this node has one of the specified flags. */
isAny(flag: CommonFlags): bool { return (this.flags & flag) != 0; }
/** Sets a specific flag or flags. */
set(flag: CommonFlags): void { this.flags |= flag; }
2017-09-28 13:08:25 +02:00
2017-12-16 17:54:53 +01:00
// types
2017-09-28 13:08:25 +02:00
static createType(
name: IdentifierExpression,
typeArguments: CommonTypeNode[] | null,
isNullable: bool,
range: Range
): TypeNode {
var type = new TypeNode();
2017-09-28 13:08:25 +02:00
type.range = range;
type.name = name; name.parent = type;
type.typeArguments = typeArguments; if (typeArguments) setParent(typeArguments, type);
2017-12-16 17:54:53 +01:00
type.isNullable = isNullable;
2017-09-28 13:08:25 +02:00
return type;
}
static createOmittedType(
range: Range
2018-03-13 14:03:57 +01:00
): TypeNode {
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,
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.parameters = 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);
stmt.decoratorKind = expression.kind == NodeKind.IDENTIFIER
? stringToDecoratorKind((<IdentifierExpression>expression).text)
: DecoratorKind.CUSTOM;
return stmt;
}
static createComment(
text: string,
kind: CommentKind,
range: Range
): CommentNode {
var node = new CommentNode();
node.range = range;
node.commentKind = kind;
node.text = text;
return node;
}
2017-12-16 17:54:53 +01:00
// expressions
2017-09-28 13:08:25 +02:00
static createIdentifierExpression(
name: string,
range: Range
): IdentifierExpression {
var expr = new IdentifierExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.text = name;
2017-09-28 13:08:25 +02:00
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();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.elementExpressions = elements; setParentIfNotNull(elements, expr);
2017-09-28 13:08:25 +02:00
return expr;
}
static createAssertionExpression(
assertionKind: AssertionKind,
expression: Expression,
toType: CommonTypeNode,
range: Range
): AssertionExpression {
var expr = new AssertionExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.assertionKind = assertionKind;
expr.expression = expression; expression.parent = expr;
expr.toType = toType; toType.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createBinaryExpression(
operator: Token,
left: Expression,
right: Expression,
range: Range
): BinaryExpression {
var expr = new BinaryExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.operator = operator;
expr.left = left; left.parent = expr;
expr.right = right; right.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createCallExpression(
expression: Expression,
typeArgs: CommonTypeNode[] | null,
args: Expression[],
range: Range
): CallExpression {
var expr = new CallExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.expression = expression; expression.parent = expr;
expr.typeArguments = typeArgs; if (typeArgs) setParent(typeArgs, expr);
expr.arguments = args; setParent(args, expr);
2017-09-28 13:08:25 +02:00
return expr;
}
static createCommaExpression(
expressions: Expression[],
range: Range
): CommaExpression {
2018-01-05 01:55:59 +01:00
var expr = new CommaExpression();
expr.range = range;
expr.expressions = expressions; setParent(expressions, expr);
2018-01-05 01:55:59 +01:00
return expr;
}
static createConstructorExpression(
range: Range
): ConstructorExpression {
var expr = new ConstructorExpression();
2017-12-16 02:27:39 +01:00
expr.range = range;
return expr;
}
static createElementAccessExpression(
expression: Expression,
element: Expression,
range: Range
): ElementAccessExpression {
var expr = new ElementAccessExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.expression = expression; expression.parent = expr;
expr.elementExpression = element; element.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createFalseExpression(
range: Range
): FalseExpression {
var expr = new FalseExpression();
2017-10-07 14:29:43 +02:00
expr.range = range;
return expr;
}
static createFloatLiteralExpression(
value: f64,
range: Range
): FloatLiteralExpression {
var expr = new FloatLiteralExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.value = value;
return expr;
}
2018-02-27 00:30:04 +01:00
static createFunctionExpression(
declaration: FunctionDeclaration
2018-02-27 00:30:04 +01:00
): FunctionExpression {
var expr = new FunctionExpression();
expr.flags = declaration.flags & CommonFlags.ARROW;
2018-02-27 00:30:04 +01:00
expr.range = declaration.range;
expr.declaration = declaration;
return expr;
}
static createIntegerLiteralExpression(
value: I64,
range: Range
): IntegerLiteralExpression {
var expr = new IntegerLiteralExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.value = value;
return expr;
}
static createNewExpression(
expression: Expression,
typeArgs: CommonTypeNode[] | null,
args: Expression[],
range: Range
): NewExpression {
var expr = new NewExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.expression = expression; expression.parent = expr;
expr.typeArguments = typeArgs; if (typeArgs) setParent(typeArgs, expr);
expr.arguments = args; setParent(args, expr);
2017-09-28 13:08:25 +02:00
return expr;
}
static createNullExpression(
range: Range
): NullExpression {
var expr = new NullExpression();
2017-10-07 14:29:43 +02:00
expr.range = range;
return expr;
}
static createParenthesizedExpression(
expression: Expression,
range: Range
): ParenthesizedExpression {
var expr = new ParenthesizedExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.expression = expression; expression.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createPropertyAccessExpression(
expression: Expression,
property: IdentifierExpression,
range: Range
): PropertyAccessExpression {
var expr = new PropertyAccessExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.expression = expression; expression.parent = expr;
expr.property = property; property.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createRegexpLiteralExpression(
pattern: string,
flags: string,
range: Range
): RegexpLiteralExpression {
var expr = new RegexpLiteralExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.pattern = pattern;
2018-01-07 18:15:21 +01:00
expr.patternFlags = flags;
2017-09-28 13:08:25 +02:00
return expr;
}
static createTernaryExpression(
condition: Expression,
ifThen: Expression,
ifElse: Expression,
range: Range
): TernaryExpression {
var expr = new TernaryExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.condition = condition; condition.parent = expr;
expr.ifThen = ifThen; ifThen.parent = expr;
expr.ifElse = ifElse; ifElse.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createStringLiteralExpression(
value: string,
range: Range
): StringLiteralExpression {
var expr = new StringLiteralExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.value = value;
return expr;
}
static createSuperExpression(
range: Range
): SuperExpression {
var expr = new SuperExpression();
2017-10-07 14:29:43 +02:00
expr.range = range;
return expr;
}
static createThisExpression(
range: Range
): ThisExpression {
var expr = new ThisExpression();
2017-10-07 14:29:43 +02:00
expr.range = range;
return expr;
}
static createTrueExpression(
range: Range
): TrueExpression {
var expr = new TrueExpression();
2017-10-07 14:29:43 +02:00
expr.range = range;
return expr;
}
static createUnaryPostfixExpression(
operator: Token,
operand: Expression,
range: Range
): UnaryPostfixExpression {
var expr = new UnaryPostfixExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.operator = operator;
expr.operand = operand; operand.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
static createUnaryPrefixExpression(
operator: Token,
operand: Expression,
range: Range
): UnaryPrefixExpression {
var expr = new UnaryPrefixExpression();
2017-09-28 13:08:25 +02:00
expr.range = range;
expr.operator = operator;
expr.operand = operand; operand.parent = expr;
2017-09-28 13:08:25 +02:00
return expr;
}
2017-12-16 17:54:53 +01:00
// statements
2017-12-16 02:27:39 +01:00
static createBlockStatement(
statements: Statement[],
range: Range
): BlockStatement {
var stmt = new BlockStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.statements = statements; setParent(statements, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
2017-12-16 02:27:39 +01:00
}
2017-09-28 13:08:25 +02:00
static createBreakStatement(
label: IdentifierExpression | null,
range: Range
): BreakStatement {
var stmt = new BreakStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.label = label; if (label) label.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createClassDeclaration(
identifier: IdentifierExpression,
typeParameters: TypeParameterNode[],
extendsType: TypeNode | null, // can't be a function
implementsTypes: TypeNode[] | null, // can't be functions
members: DeclarationStatement[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): ClassDeclaration {
var stmt = new ClassDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = identifier; identifier.parent = stmt;
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.implementsTypes = implementsTypes; if (implementsTypes) setParent(implementsTypes, stmt);
stmt.members = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createContinueStatement(
label: IdentifierExpression | null,
range: Range
): ContinueStatement {
var stmt = new ContinueStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.label = label; if (label) label.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createDoStatement(
statement: Statement,
condition: Expression,
range: Range
): DoStatement {
var stmt = new DoStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.statement = statement; statement.parent = stmt;
stmt.condition = condition; condition.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createEmptyStatement(
range: Range
): EmptyStatement {
var stmt = new EmptyStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
return stmt;
}
2017-09-28 13:08:25 +02:00
static createEnumDeclaration(
name: IdentifierExpression,
members: EnumValueDeclaration[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): EnumDeclaration {
var stmt = new EnumDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.values = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createEnumValueDeclaration(
name: IdentifierExpression,
value: Expression | null,
flags: CommonFlags,
range: Range
): EnumValueDeclaration {
var stmt = new EnumValueDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.value = value; if (value) value.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
2017-09-28 13:08:25 +02:00
}
static createExportStatement(
members: ExportMember[],
path: StringLiteralExpression | null,
flags: CommonFlags,
range: Range
): ExportStatement {
var stmt = new ExportStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.members = members; setParent(members, stmt);
2017-12-16 17:54:53 +01:00
stmt.path = path;
if (path) {
let normalizedPath = normalizePath(path.value);
2018-02-25 00:13:39 +01:00
if (path.value.startsWith(".")) { // relative
stmt.normalizedPath = resolvePath(
normalizedPath,
range.source.normalizedPath
);
2018-02-25 00:13:39 +01:00
} else { // absolute
stmt.normalizedPath = normalizedPath;
2018-02-25 00:13:39 +01:00
}
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
} else {
stmt.normalizedPath = null;
stmt.internalPath = null;
}
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createExportImportStatement(
name: IdentifierExpression,
externalName: IdentifierExpression,
range: Range
): ExportImportStatement {
var stmt = new ExportImportStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.name = name; name.parent = stmt;
stmt.externalName = externalName; externalName.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createExportMember(
name: IdentifierExpression,
externalName: IdentifierExpression | null,
range: Range
): ExportMember {
var elem = new ExportMember();
2017-12-16 17:54:53 +01:00
elem.range = range;
elem.name = name; name.parent = elem;
2018-02-25 00:13:39 +01:00
if (!externalName) {
externalName = name;
2018-02-25 00:13:39 +01:00
} else {
externalName.parent = elem;
2018-02-25 00:13:39 +01:00
}
elem.externalName = externalName;
2017-12-16 17:54:53 +01:00
return elem;
2017-09-28 13:08:25 +02:00
}
static createExpressionStatement(
expression: Expression
): ExpressionStatement {
var stmt = new ExpressionStatement();
2017-12-16 17:54:53 +01:00
stmt.range = expression.range;
stmt.expression = expression; expression.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createIfStatement(
condition: Expression,
ifTrue: Statement,
ifFalse: Statement | null,
range: Range
): IfStatement {
var stmt = new IfStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.condition = condition; condition.parent = stmt;
stmt.ifTrue = ifTrue; ifTrue.parent = stmt;
stmt.ifFalse = ifFalse; if (ifFalse) ifFalse.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
2017-09-28 13:08:25 +02:00
static createImportStatement(
decls: ImportDeclaration[] | null,
path: StringLiteralExpression,
range: Range
): ImportStatement {
var stmt = new ImportStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.declarations = decls; if (decls) setParent(decls, stmt);
stmt.namespaceName = null;
stmt.path = path;
var normalizedPath = normalizePath(path.value);
if (path.value.startsWith(".")) { // relative in project
stmt.normalizedPath = resolvePath(
normalizedPath,
range.source.normalizedPath
);
} else { // absolute in library
if (!normalizedPath.startsWith(LIBRARY_PREFIX)) {
normalizedPath = LIBRARY_PREFIX + normalizedPath;
}
stmt.normalizedPath = normalizedPath;
2018-02-25 00:13:39 +01:00
}
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
return stmt;
}
static createImportStatementWithWildcard(
identifier: IdentifierExpression,
path: StringLiteralExpression,
range: Range
): ImportStatement {
var stmt = new ImportStatement();
stmt.range = range;
stmt.declarations = null;
stmt.namespaceName = identifier;
2017-12-16 17:54:53 +01:00
stmt.path = path;
stmt.normalizedPath = resolvePath(
normalizePath(path.value),
range.source.normalizedPath
);
2017-12-16 17:54:53 +01:00
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
return stmt;
2017-09-28 13:08:25 +02:00
}
static createImportDeclaration(
externalName: IdentifierExpression,
name: IdentifierExpression | null,
range: Range
): ImportDeclaration {
var elem = new ImportDeclaration();
2017-12-16 17:54:53 +01:00
elem.range = range;
elem.externalName = externalName; externalName.parent = elem;
2018-02-25 00:13:39 +01:00
if (!name) {
name = externalName;
2018-02-25 00:13:39 +01:00
} else {
name.parent = elem;
2018-02-25 00:13:39 +01:00
}
elem.name = name;
2017-12-16 17:54:53 +01:00
return elem;
}
static createInterfaceDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameterNode[],
extendsType: TypeNode | null, // can't be a function
members: DeclarationStatement[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): InterfaceDeclaration {
var stmt = new InterfaceDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.members = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createFieldDeclaration(
name: IdentifierExpression,
type: CommonTypeNode | null,
initializer: Expression | null,
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): FieldDeclaration {
var stmt = new FieldDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.type = type; if (type) type.parent = stmt;
stmt.initializer = initializer; if (initializer) initializer.parent = stmt;
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createForStatement(
initializer: Statement | null,
condition: Expression | null,
incrementor: Expression | null,
statement: Statement,
range: Range
): ForStatement {
var stmt = new ForStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.initializer = initializer; if (initializer) initializer.parent = stmt;
stmt.condition = condition; if (condition) condition.parent = stmt;
stmt.incrementor = incrementor; if (incrementor) incrementor.parent = stmt;
stmt.statement = statement; statement.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
static createFunctionDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameterNode[] | null,
signature: SignatureNode,
2018-02-27 00:30:04 +01:00
body: Statement | null,
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): FunctionDeclaration {
var stmt = new FunctionDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.signature = signature; signature.parent = stmt;
2018-02-27 00:30:04 +01:00
stmt.body = body; if (body) body.parent = stmt;
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createMethodDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameterNode[] | null,
signature: SignatureNode,
2018-02-27 00:30:04 +01:00
body: Statement | null,
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): MethodDeclaration {
var stmt = new MethodDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.signature = signature; signature.parent = stmt;
2018-02-27 00:30:04 +01:00
stmt.body = body; if (body) body.parent = stmt;
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createNamespaceDeclaration(
name: IdentifierExpression,
members: Statement[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): NamespaceDeclaration {
var stmt = new NamespaceDeclaration();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.members = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createReturnStatement(
value: Expression | null,
range: Range
): ReturnStatement {
var stmt = new ReturnStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.value = value; if (value) value.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
static createSwitchStatement(
condition: Expression,
cases: SwitchCase[],
range: Range
): SwitchStatement {
var stmt = new SwitchStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.condition = condition; condition.parent = stmt;
stmt.cases = cases; setParent(cases, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createSwitchCase(
label: Expression | null,
statements: Statement[],
range: Range
): SwitchCase {
var elem = new SwitchCase();
2017-12-16 17:54:53 +01:00
elem.range = range;
elem.label = label; if (label) label.parent = elem;
elem.statements = statements; setParent(statements, elem);
2017-12-16 17:54:53 +01:00
return elem;
}
static createThrowStatement(
value: Expression,
range: Range
): ThrowStatement {
var stmt = new ThrowStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.value = value; value.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
static createTryStatement(
statements: Statement[],
catchVariable: IdentifierExpression | null,
catchStatements: Statement[] | null,
finallyStatements: Statement[] | null,
range: Range
): TryStatement {
var stmt = new TryStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.statements = statements; setParent(statements, stmt);
stmt.catchVariable = catchVariable;
if (catchVariable) catchVariable.parent = stmt;
stmt.catchStatements = catchStatements;
if (catchStatements) setParent(catchStatements, stmt);
stmt.finallyStatements = finallyStatements;
if (finallyStatements) setParent(finallyStatements, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createTypeDeclaration(
name: IdentifierExpression,
2018-03-12 17:44:09 +01:00
typeParameters: TypeParameterNode[] | null,
alias: CommonTypeNode,
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): TypeDeclaration {
var stmt = new TypeDeclaration();
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
2018-03-12 17:44:09 +01:00
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.type = alias; alias.parent = stmt;
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt;
}
static createVariableStatement(
declarations: VariableDeclaration[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): VariableStatement {
var stmt = new VariableStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.flags = flags;
stmt.declarations = declarations; setParent(declarations, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
2017-12-16 17:54:53 +01:00
return stmt;
}
static createVariableDeclaration(
name: IdentifierExpression,
type: CommonTypeNode | null,
initializer: Expression | null,
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): VariableDeclaration {
var elem = new VariableDeclaration();
2017-12-16 17:54:53 +01:00
elem.range = range;
elem.flags = flags;
elem.name = name; name.parent = elem;
elem.type = type; if (type) type.parent = elem;
elem.initializer = initializer; if (initializer) initializer.parent = elem;
elem.decorators = decorators; // inherited
2017-12-16 17:54:53 +01:00
return elem;
}
static createVoidStatement(
expression: Expression,
range: Range
): VoidStatement {
var stmt = new VoidStatement();
stmt.range = range;
stmt.expression = expression;
return stmt;
}
static createWhileStatement(
condition: Expression,
statement: Statement,
range: Range
): WhileStatement {
var stmt = new WhileStatement();
2017-12-16 17:54:53 +01:00
stmt.range = range;
stmt.condition = condition; condition.parent = stmt;
stmt.statement = statement; statement.parent = stmt;
2017-12-16 17:54:53 +01:00
return stmt;
}
}
// types
export abstract class CommonTypeNode extends Node {
// kind varies
/** Whether nullable or not. */
isNullable: bool;
}
2017-12-16 17:54:53 +01:00
/** Represents a type annotation. */
export class TypeNode extends CommonTypeNode {
2017-12-16 17:54:53 +01:00
kind = NodeKind.TYPE;
/** Identifier reference. */
name: IdentifierExpression;
2017-12-16 17:54:53 +01:00
/** Type argument references. */
typeArguments: CommonTypeNode[] | null;
2017-12-16 17:54:53 +01:00
}
/** Represents a type parameter. */
export class TypeParameterNode extends Node {
2017-12-16 17:54:53 +01:00
kind = NodeKind.TYPEPARAMETER;
/** Identifier reference. */
name: IdentifierExpression;
2017-12-16 17:54:53 +01:00
/** Extended type reference, if any. */
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;
/** Initializer expression, if present. */
initializer: Expression | null;
/** Implicit field declaration, if applicable. */
implicitFieldDeclaration: FieldDeclaration | null = null;
}
/** Represents a function signature. */
export class SignatureNode extends CommonTypeNode {
kind = NodeKind.SIGNATURE;
/** Accepted parameters. */
parameters: ParameterNode[];
/** Return type. */
returnType: CommonTypeNode;
/** Explicitly provided this type, if any. */
explicitThisType: TypeNode | null; // can't be a function
}
// special
/** Built-in decorator kinds. */
export enum DecoratorKind {
CUSTOM,
GLOBAL,
OPERATOR,
UNMANAGED,
SEALED,
INLINE
}
/** Returns the decorator kind represented by the specified string. */
export function stringToDecoratorKind(str: string): DecoratorKind {
assert(str.length);
switch (str.charCodeAt(0)) {
case CharCode.g: {
if (str == "global") return DecoratorKind.GLOBAL;
break;
}
case CharCode.i: {
if (str == "inline") return DecoratorKind.INLINE;
break;
}
case CharCode.o: {
if (str == "operator") return DecoratorKind.OPERATOR;
break;
}
case CharCode.s: {
if (str == "sealed") return DecoratorKind.SEALED;
break;
}
case CharCode.u: {
if (str == "unmanaged") return DecoratorKind.UNMANAGED;
break;
}
}
return DecoratorKind.CUSTOM;
}
/** Represents 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;
}
/** Comment kinds. */
export enum CommentKind {
/** Line comment. */
LINE,
/** Triple-slash comment. */
TRIPLE,
/** Block comment. */
BLOCK
}
/** Represents a comment. */
export class CommentNode extends Node {
kind = NodeKind.COMMENT;
/** Comment kind. */
commentKind: CommentKind;
/** Comment text. */
text: string;
}
2017-12-16 17:54:53 +01:00
// expressions
/** Base class of all expression nodes. */
export abstract class Expression extends Node { }
2017-12-18 03:46:36 +01:00
/** Represents an identifier expression. */
2017-12-16 17:54:53 +01:00
export class IdentifierExpression extends Expression {
kind = NodeKind.IDENTIFIER;
2017-12-18 03:46:36 +01:00
/** Textual name. */
text: string;
2017-12-16 17:54:53 +01:00
}
2017-12-18 03:46:36 +01:00
/** Indicates the kind of a literal. */
export enum LiteralKind {
2017-12-16 17:54:53 +01:00
FLOAT,
INTEGER,
STRING,
REGEXP,
ARRAY,
OBJECT
}
2017-12-18 03:46:36 +01:00
/** Base class of all literal expressions. */
2017-12-16 17:54:53 +01:00
export abstract class LiteralExpression extends Expression {
kind = NodeKind.LITERAL;
2017-12-18 03:46:36 +01:00
/** Specific literal kind. */
2017-12-16 17:54:53 +01:00
literalKind: LiteralKind;
}
2017-12-18 03:46:36 +01:00
/** Represents an `[]` literal expression. */
2017-12-16 17:54:53 +01:00
export class ArrayLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.ARRAY;
2017-12-18 03:46:36 +01:00
/** Nested element expressions. */
2017-12-16 17:54:53 +01:00
elementExpressions: (Expression | null)[];
}
2017-12-18 03:46:36 +01:00
/** Indicates the kind of an assertion. */
export enum AssertionKind {
2017-12-16 17:54:53 +01:00
PREFIX,
AS
}
2017-12-18 03:46:36 +01:00
/** Represents an assertion expression. */
2017-12-16 17:54:53 +01:00
export class AssertionExpression extends Expression {
kind = NodeKind.ASSERTION;
2017-12-18 03:46:36 +01:00
/** Specific kind of this assertion. */
2017-12-16 17:54:53 +01:00
assertionKind: AssertionKind;
2017-12-18 03:46:36 +01:00
/** Expression being asserted. */
2017-12-16 17:54:53 +01:00
expression: Expression;
2017-12-18 03:46:36 +01:00
/** Target type. */
toType: CommonTypeNode;
2017-12-16 17:54:53 +01:00
}
2017-12-18 03:46:36 +01:00
/** Represents a binary expression. */
2017-12-16 17:54:53 +01:00
export class BinaryExpression extends Expression {
kind = NodeKind.BINARY;
2017-12-18 03:46:36 +01:00
/** Operator token. */
2017-12-16 17:54:53 +01:00
operator: Token;
2017-12-18 03:46:36 +01:00
/** Left-hand side expression */
2017-12-16 17:54:53 +01:00
left: Expression;
2017-12-18 03:46:36 +01:00
/** Right-hand side expression. */
2017-12-16 17:54:53 +01:00
right: Expression;
}
2017-12-18 03:46:36 +01:00
/** Represents a call expression. */
2017-12-16 17:54:53 +01:00
export class CallExpression extends Expression {
kind = NodeKind.CALL;
2017-12-18 03:46:36 +01:00
/** Called expression. Usually an identifier or property access expression. */
2017-12-16 17:54:53 +01:00
expression: Expression;
2017-12-18 03:46:36 +01:00
/** Provided type arguments. */
typeArguments: CommonTypeNode[] | null;
2017-12-18 03:46:36 +01:00
/** Provided arguments. */
2017-12-16 17:54:53 +01:00
arguments: Expression[];
}
2018-02-25 00:13:39 +01:00
/** Represents a comma expression composed of multiple expressions. */
2018-01-05 01:55:59 +01:00
export class CommaExpression extends Expression {
kind = NodeKind.COMMA;
/** Sequential expressions. */
expressions: Expression[];
}
2017-12-18 03:46:36 +01:00
/** Represents a `constructor` expression. */
2017-12-16 17:54:53 +01:00
export class ConstructorExpression extends IdentifierExpression {
kind = NodeKind.CONSTRUCTOR;
text = "constructor";
2017-12-16 02:27:39 +01:00
}
2017-12-18 03:46:36 +01:00
/** Represents an element access expression, e.g., array access. */
2017-09-28 13:08:25 +02:00
export class ElementAccessExpression extends Expression {
kind = NodeKind.ELEMENTACCESS;
2017-12-18 03:46:36 +01:00
/** Expression being accessed. */
2017-09-28 13:08:25 +02:00
expression: Expression;
2017-12-18 03:46:36 +01:00
/** Element of the expression being accessed. */
2017-09-28 13:08:25 +02:00
elementExpression: Expression;
}
2017-12-18 03:46:36 +01:00
/** Represents a float literal expression. */
2017-09-28 13:08:25 +02:00
export class FloatLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.FLOAT;
2017-12-18 03:46:36 +01:00
/** Float value. */
2017-09-28 13:08:25 +02:00
value: f64;
}
2018-02-27 00:30:04 +01:00
/** Represents a function expression using the 'function' keyword. */
export class FunctionExpression extends Expression {
kind = NodeKind.FUNCTION;
/** Inline function declaration. */
declaration: FunctionDeclaration;
}
2017-12-18 03:46:36 +01:00
/** Represents an integer literal expression. */
2017-09-28 13:08:25 +02:00
export class IntegerLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.INTEGER;
2017-12-18 03:46:36 +01:00
/** Integer value. */
2017-09-28 13:08:25 +02:00
value: I64;
}
2017-12-18 03:46:36 +01:00
/** Represents a `new` expression. Like a call but with its own kind. */
2017-09-28 13:08:25 +02:00
export class NewExpression extends CallExpression {
kind = NodeKind.NEW;
}
2017-12-18 03:46:36 +01:00
/** Represents a `null` expression. */
2017-10-07 14:29:43 +02:00
export class NullExpression extends IdentifierExpression {
kind = NodeKind.NULL;
text = "null";
2017-10-07 14:29:43 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a parenthesized expression. */
2017-09-28 13:08:25 +02:00
export class ParenthesizedExpression extends Expression {
kind = NodeKind.PARENTHESIZED;
2017-12-18 03:46:36 +01:00
/** Expression in parenthesis. */
2017-09-28 13:08:25 +02:00
expression: Expression;
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a property access expression. */
2017-12-16 17:54:53 +01:00
export class PropertyAccessExpression extends Expression {
kind = NodeKind.PROPERTYACCESS;
2017-12-18 03:46:36 +01:00
/** Expression being accessed. */
2017-12-16 17:54:53 +01:00
expression: Expression;
2017-12-18 03:46:36 +01:00
/** Property of the expression being accessed. */
2017-12-16 17:54:53 +01:00
property: IdentifierExpression;
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a regular expression literal expression. */
2017-12-16 17:54:53 +01:00
export class RegexpLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.REGEXP;
2017-12-18 03:46:36 +01:00
/** Regular expression pattern. */
pattern: string;
2018-01-07 18:15:21 +01:00
/** Regular expression flags. */
patternFlags: string;
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a ternary expression, i.e., short if notation. */
2017-12-16 17:54:53 +01:00
export class TernaryExpression extends Expression {
kind = NodeKind.TERNARY;
2017-12-18 03:46:36 +01:00
/** Condition expression. */
2017-12-16 17:54:53 +01:00
condition: Expression;
2017-12-18 03:46:36 +01:00
/** Expression executed when condition is `true`. */
2017-12-16 17:54:53 +01:00
ifThen: Expression;
2017-12-18 03:46:36 +01:00
/** Expression executed when condition is `false`. */
2017-12-16 17:54:53 +01:00
ifElse: Expression;
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a string literal expression. */
2017-12-16 17:54:53 +01:00
export class StringLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.STRING;
2017-12-18 03:46:36 +01:00
/** String value without quotes. */
2017-12-16 17:54:53 +01:00
value: string;
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a `super` expression. */
2017-12-16 17:54:53 +01:00
export class SuperExpression extends IdentifierExpression {
kind = NodeKind.SUPER;
text = "super";
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a `this` expression. */
2017-12-16 17:54:53 +01:00
export class ThisExpression extends IdentifierExpression {
kind = NodeKind.THIS;
text = "this";
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a `true` expression. */
2017-12-16 17:54:53 +01:00
export class TrueExpression extends IdentifierExpression {
kind = NodeKind.TRUE;
text = "true";
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a `false` expression. */
2017-12-16 17:54:53 +01:00
export class FalseExpression extends IdentifierExpression {
kind = NodeKind.FALSE;
text = "false";
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Base class of all unary expressions. */
2017-12-16 17:54:53 +01:00
export abstract class UnaryExpression extends Expression {
2017-12-18 03:46:36 +01:00
/** Operator token. */
2017-12-16 17:54:53 +01:00
operator: Token;
2017-12-18 03:46:36 +01:00
/** Operand expression. */
operand: Expression;
2017-12-16 17:54:53 +01:00
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a unary postfix expression, e.g. a postfix increment. */
2017-12-16 17:54:53 +01:00
export class UnaryPostfixExpression extends UnaryExpression {
kind = NodeKind.UNARYPOSTFIX;
}
2017-09-28 13:08:25 +02:00
2017-12-18 03:46:36 +01:00
/** Represents a unary prefix expression, e.g. a negation. */
2017-12-16 17:54:53 +01:00
export class UnaryPrefixExpression extends UnaryExpression {
kind = NodeKind.UNARYPREFIX;
2017-09-28 13:08:25 +02:00
}
2017-12-16 17:54:53 +01:00
// statements
/** Base class of all statement nodes. */
export abstract class Statement extends Node { }
/** Indicates the specific kind of a source. */
export enum SourceKind {
/** Default source. Usually imported from an entry file. */
DEFAULT,
/** Entry file. */
ENTRY,
/** Library file. */
LIBRARY
}
2017-12-18 03:46:36 +01:00
/** A top-level source node. */
2017-10-02 12:52:15 +02:00
export class Source extends Node {
2017-09-28 13:08:25 +02:00
kind = NodeKind.SOURCE;
parent = null;
2017-12-18 03:46:36 +01:00
/** Source kind. */
sourceKind: SourceKind;
2017-12-18 03:46:36 +01:00
/** Normalized path. */
2017-10-02 12:52:15 +02:00
normalizedPath: string;
2017-12-18 03:46:36 +01:00
/** Path used internally. */
internalPath: string;
2017-12-18 03:46:36 +01:00
/** Contained statements. */
2017-09-28 13:08:25 +02:00
statements: Statement[];
2017-12-18 03:46:36 +01:00
/** Full source text. */
2017-10-02 12:52:15 +02:00
text: string;
2017-12-18 03:46:36 +01:00
/** Tokenizer reference. */
2017-10-02 12:52:15 +02:00
tokenizer: Tokenizer | null = null;
/** Source map index. */
debugInfoIndex: i32 = -1;
2017-10-02 12:52:15 +02:00
2017-12-18 03:46:36 +01:00
/** Constructs a new source node. */
constructor(normalizedPath: string, text: string, kind: SourceKind) {
2017-10-02 12:52:15 +02:00
super();
this.sourceKind = kind;
this.normalizedPath = normalizedPath;
this.internalPath = mangleInternalPath(this.normalizedPath);
2017-10-02 12:52:15 +02:00
this.statements = new Array();
this.range = new Range(this, 0, text.length);
this.text = text;
}
/** Tests if this source is an entry file. */
get isEntry(): bool { return this.sourceKind == SourceKind.ENTRY; }
/** Tests if this source is a stdlib file. */
get isLibrary(): bool { return this.sourceKind == SourceKind.LIBRARY; }
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Base class of all declaration statements. */
2017-09-28 13:08:25 +02:00
export abstract class DeclarationStatement extends Statement {
2017-12-18 03:46:36 +01:00
/** Simple name being declared. */
name: IdentifierExpression;
/** Array of decorators. */
decorators: DecoratorNode[] | null = null;
protected cachedProgramLevelInternalName: string | null = null;
protected cachedFileLevelInternalName: string | null = null;
/** Gets the mangled program-level internal name of this declaration. */
get programLevelInternalName(): string {
2018-02-25 00:13:39 +01:00
if (!this.cachedProgramLevelInternalName) {
this.cachedProgramLevelInternalName = mangleInternalName(this, true);
2018-02-25 00:13:39 +01:00
}
return this.cachedProgramLevelInternalName;
}
/** Gets the mangled file-level internal name of this declaration. */
get fileLevelInternalName(): string {
2018-02-25 00:13:39 +01:00
if (!this.cachedFileLevelInternalName) {
this.cachedFileLevelInternalName = mangleInternalName(this, false);
2018-02-25 00:13:39 +01:00
}
return this.cachedFileLevelInternalName;
}
/** Tests if this is a top-level declaration within its source file. */
get isTopLevel(): bool {
var parent = this.parent;
2018-02-25 00:13:39 +01:00
if (!parent) {
return false;
2018-02-25 00:13:39 +01:00
}
if (parent.kind == NodeKind.VARIABLE && !(parent = parent.parent)) {
return false;
}
return parent.kind == NodeKind.SOURCE;
}
/** Tests if this declaration is a top-level export within its source file. */
get isTopLevelExport(): bool {
var parent = this.parent;
2018-02-25 00:13:39 +01:00
if (!parent || (parent.kind == NodeKind.VARIABLE && !(parent = parent.parent))) {
return false;
2018-02-25 00:13:39 +01:00
}
if (parent.kind == NodeKind.NAMESPACEDECLARATION) {
return this.is(CommonFlags.EXPORT) && (<NamespaceDeclaration>parent).isTopLevelExport;
2018-02-25 00:13:39 +01:00
}
if (parent.kind == NodeKind.CLASSDECLARATION) {
return this.is(CommonFlags.STATIC) && (<ClassDeclaration>parent).isTopLevelExport;
2018-02-25 00:13:39 +01:00
}
return parent.kind == NodeKind.SOURCE && this.is(CommonFlags.EXPORT);
}
/** Tests if this declaration needs an explicit export. */
needsExplicitExport(member: ExportMember): bool {
// This is necessary because module-level exports are automatically created
// for top level declarations of all sorts. This function essentially tests
// that there isn't a otherwise duplicate top-level export already.
return (
member.name.text != member.externalName.text || // if aliased
this.range.source != member.range.source || // if a re-export
!this.isTopLevelExport // if not top-level
);
}
}
/** Base class of all variable-like declaration statements. */
export abstract class VariableLikeDeclarationStatement extends DeclarationStatement {
2017-12-18 03:46:36 +01:00
/** Variable type. */
type: CommonTypeNode | null;
2017-12-18 03:46:36 +01:00
/** Variable initializer. */
initializer: Expression | null;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a block statement. */
2017-09-28 13:08:25 +02:00
export class BlockStatement extends Statement {
kind = NodeKind.BLOCK;
2017-12-18 03:46:36 +01:00
/** Contained statements. */
2017-09-28 13:08:25 +02:00
statements: Statement[];
}
2017-12-18 03:46:36 +01:00
/** Represents a `break` statement. */
2017-09-28 13:08:25 +02:00
export class BreakStatement extends Statement {
kind = NodeKind.BREAK;
2017-12-18 03:46:36 +01:00
/** Target label, if applicable. */
2017-09-28 13:08:25 +02:00
label: IdentifierExpression | null;
}
2017-12-18 03:46:36 +01:00
/** Represents a `class` declaration. */
2017-09-28 13:08:25 +02:00
export class ClassDeclaration extends DeclarationStatement {
kind = NodeKind.CLASSDECLARATION;
2017-12-18 03:46:36 +01:00
/** Accepted type parameters. */
typeParameters: TypeParameterNode[];
/** Base class type being extended, if any. */
extendsType: TypeNode | null; // can't be a function
/** Interface types being implemented, if any. */
implementsTypes: TypeNode[] | null; // can't be functions
2017-12-18 03:46:36 +01:00
/** Class member declarations. */
2017-09-28 13:08:25 +02:00
members: DeclarationStatement[];
get isGeneric(): bool {
var typeParameters = this.typeParameters;
return typeParameters != null && typeParameters.length > 0;
}
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a `continue` statement. */
2017-09-28 13:08:25 +02:00
export class ContinueStatement extends Statement {
kind = NodeKind.CONTINUE;
2017-12-18 03:46:36 +01:00
/** Target label, if applicable. */
2017-09-28 13:08:25 +02:00
label: IdentifierExpression | null;
}
2017-12-18 03:46:36 +01:00
/** Represents a `do` statement. */
2017-09-28 13:08:25 +02:00
export class DoStatement extends Statement {
kind = NodeKind.DO;
2017-12-18 03:46:36 +01:00
/** Statement being looped over. */
2017-09-28 13:08:25 +02:00
statement: Statement;
2017-12-18 03:46:36 +01:00
/** Condition when to repeat. */
2017-09-28 13:08:25 +02:00
condition: Expression;
}
2017-12-18 03:46:36 +01:00
/** Represents an empty statement, i.e., a semicolon terminating nothing. */
2017-09-28 13:08:25 +02:00
export class EmptyStatement extends Statement {
kind = NodeKind.EMPTY;
}
2017-12-18 03:46:36 +01:00
/** Represents an `enum` declaration. */
2017-09-28 13:08:25 +02:00
export class EnumDeclaration extends DeclarationStatement {
kind = NodeKind.ENUMDECLARATION;
2017-12-18 03:46:36 +01:00
/** Enum value declarations. */
values: EnumValueDeclaration[];
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a value of an `enum` declaration. */
2017-09-28 13:08:25 +02:00
export class EnumValueDeclaration extends DeclarationStatement {
kind = NodeKind.ENUMVALUEDECLARATION;
2017-12-18 03:46:36 +01:00
// name is inherited
/** Value expression. */
2017-09-28 13:08:25 +02:00
value: Expression | null;
}
2017-12-18 03:46:36 +01:00
/** Represents an `export import` statement of an interface. */
2017-09-28 13:08:25 +02:00
export class ExportImportStatement extends Node {
kind = NodeKind.EXPORTIMPORT;
2017-12-18 03:46:36 +01:00
/** Identifier being imported. */
name: IdentifierExpression;
2017-12-18 03:46:36 +01:00
/** Identifier being exported. */
externalName: IdentifierExpression;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a member of an `export` statement. */
2017-09-28 13:08:25 +02:00
export class ExportMember extends Node {
kind = NodeKind.EXPORTMEMBER;
2017-12-18 03:46:36 +01:00
/** Identifier being exported. */
name: IdentifierExpression;
2017-12-18 03:46:36 +01:00
/** Identifier seen when imported again. */
externalName: IdentifierExpression;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents an `export` statement. */
2017-09-28 13:08:25 +02:00
export class ExportStatement extends Statement {
kind = NodeKind.EXPORT;
2017-12-18 03:46:36 +01:00
/** Array of members. */
2017-09-28 13:08:25 +02:00
members: ExportMember[];
2017-12-18 03:46:36 +01:00
/** Path being exported from, if applicable. */
path: StringLiteralExpression | null;
2017-12-18 03:46:36 +01:00
/** Normalized path, if `path` is set. */
2017-10-02 12:52:15 +02:00
normalizedPath: string | null;
2017-12-18 03:46:36 +01:00
/** Mangled internal path being referenced, if `path` is set. */
internalPath: string | null;
2017-09-28 13:08:25 +02:00
}
/** Represents an expression that is used as a statement. */
2017-09-28 13:08:25 +02:00
export class ExpressionStatement extends Statement {
kind = NodeKind.EXPRESSION;
2017-12-18 03:46:36 +01:00
/** Expression being used as a statement.*/
2017-09-28 13:08:25 +02:00
expression: Expression;
}
2017-12-18 03:46:36 +01:00
/** Represents a field declaration within a `class`. */
export class FieldDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.FIELDDECLARATION;
/** Parameter index within the constructor, if applicable. */
parameterIndex: i32 = -1;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a `for` statement. */
2017-09-28 13:08:25 +02:00
export class ForStatement extends Statement {
kind = NodeKind.FOR;
2017-12-18 03:46:36 +01:00
/**
* Initializer statement, if present.
* Either a {@link VariableStatement} or {@link ExpressionStatement}.
*/
2017-09-28 13:08:25 +02:00
initializer: Statement | null;
2017-12-18 03:46:36 +01:00
/** Condition expression, if present. */
2017-09-28 13:08:25 +02:00
condition: Expression | null;
2017-12-18 03:46:36 +01:00
/** Incrementor expression, if present. */
2017-09-28 13:08:25 +02:00
incrementor: Expression | null;
2017-12-18 03:46:36 +01:00
/** Statement being looped over. */
2017-09-28 13:08:25 +02:00
statement: Statement;
}
2017-12-18 03:46:36 +01:00
/** Represents a `function` declaration. */
2017-09-28 13:08:25 +02:00
export class FunctionDeclaration extends DeclarationStatement {
kind = NodeKind.FUNCTIONDECLARATION;
2017-12-18 03:46:36 +01:00
/** Type parameters, if any. */
typeParameters: TypeParameterNode[] | null;
/** Function signature. */
signature: SignatureNode;
2018-02-27 00:30:04 +01:00
/** Body statement. Usually a block. */
body: Statement | null;
get isGeneric(): bool {
var typeParameters = this.typeParameters;
return typeParameters != null && typeParameters.length > 0;
}
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents an `if` statement. */
2017-09-28 13:08:25 +02:00
export class IfStatement extends Statement {
kind = NodeKind.IF;
2017-12-18 03:46:36 +01:00
/** Condition. */
2017-09-28 13:08:25 +02:00
condition: Expression;
2017-12-18 03:46:36 +01:00
/** Statement executed when condition is `true`. */
ifTrue: Statement;
/** Statement executed when condition is `false`. */
ifFalse: Statement | null;
2017-09-28 13:08:25 +02:00
}
/** Represents an `import` declaration part of an {@link ImportStatement}. */
2017-09-28 13:08:25 +02:00
export class ImportDeclaration extends DeclarationStatement {
kind = NodeKind.IMPORTDECLARATION;
2017-12-18 03:46:36 +01:00
/** Identifier being imported. */
externalName: IdentifierExpression;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents an `import` statement. */
2017-09-28 13:08:25 +02:00
export class ImportStatement extends Statement {
kind = NodeKind.IMPORT;
2017-12-18 03:46:36 +01:00
/** Array of member declarations or `null` if an asterisk import. */
declarations: ImportDeclaration[] | null;
/** Name of the local namespace, if an asterisk import. */
namespaceName: IdentifierExpression | null;
2017-12-18 03:46:36 +01:00
/** Path being imported from. */
path: StringLiteralExpression;
2017-12-18 03:46:36 +01:00
/** Normalized path. */
2017-10-02 12:52:15 +02:00
normalizedPath: string;
2017-12-18 03:46:36 +01:00
/** Mangled internal path being referenced. */
internalPath: string;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents an `interfarce` declaration. */
export class InterfaceDeclaration extends ClassDeclaration {
kind = NodeKind.INTERFACEDECLARATION;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a method declaration within a `class`. */
2017-09-28 13:08:25 +02:00
export class MethodDeclaration extends FunctionDeclaration {
kind = NodeKind.METHODDECLARATION;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a `namespace` declaration. */
2017-09-28 13:08:25 +02:00
export class NamespaceDeclaration extends DeclarationStatement {
kind = NodeKind.NAMESPACEDECLARATION;
2017-12-18 03:46:36 +01:00
/** Array of namespace members. */
2017-10-07 14:29:43 +02:00
members: Statement[];
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a `return` statement. */
2017-09-28 13:08:25 +02:00
export class ReturnStatement extends Statement {
kind = NodeKind.RETURN;
2017-12-18 03:46:36 +01:00
/** Value expression being returned, if present. */
value: Expression | null;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a single `case` within a `switch` statement. */
2017-09-28 13:08:25 +02:00
export class SwitchCase extends Node {
kind = NodeKind.SWITCHCASE;
2017-12-18 03:46:36 +01:00
/** Label expression. `null` indicates the default case. */
label: Expression | null;
/** Contained statements. */
2017-09-28 13:08:25 +02:00
statements: Statement[];
}
2017-12-18 03:46:36 +01:00
/** Represents a `switch` statement. */
2017-09-28 13:08:25 +02:00
export class SwitchStatement extends Statement {
kind = NodeKind.SWITCH;
2017-12-18 03:46:36 +01:00
/** Condition expression. */
condition: Expression;
/** Contained cases. */
2017-09-28 13:08:25 +02:00
cases: SwitchCase[];
}
2017-12-18 03:46:36 +01:00
/** Represents a `throw` statement. */
2017-09-28 13:08:25 +02:00
export class ThrowStatement extends Statement {
kind = NodeKind.THROW;
2017-12-18 03:46:36 +01:00
/** Value expression being thrown. */
value: Expression;
2017-09-28 13:08:25 +02:00
}
2017-12-18 03:46:36 +01:00
/** Represents a `try` statement. */
2017-09-28 13:08:25 +02:00
export class TryStatement extends Statement {
kind = NodeKind.TRY;
2017-12-18 03:46:36 +01:00
/** Contained statements. */
2017-09-28 13:08:25 +02:00
statements: Statement[];
/** Exception variable name, if a `catch` clause is present. */
2017-10-07 14:29:43 +02:00
catchVariable: IdentifierExpression | null;
/** Statements being executed on catch, if a `catch` clause is present. */
2017-10-07 14:29:43 +02:00
catchStatements: Statement[] | null;
/** Statements being executed afterwards, if a `finally` clause is present. */
2017-10-07 14:29:43 +02:00
finallyStatements: Statement[] | null;
2017-09-28 13:08:25 +02:00
}
/** Represents a `type` declaration. */
export class TypeDeclaration extends DeclarationStatement {
kind = NodeKind.TYPEDECLARATION;
2018-03-12 17:44:09 +01:00
/** Type parameters, if any. */
typeParameters: TypeParameterNode[] | null;
/** Type being aliased. */
2018-03-12 17:44:09 +01:00
type: CommonTypeNode;
}
/** Represents a variable declaration part of a {@link VariableStatement}. */
export class VariableDeclaration extends VariableLikeDeclarationStatement {
2017-09-28 13:08:25 +02:00
kind = NodeKind.VARIABLEDECLARATION;
}
/** Represents a variable statement wrapping {@link VariableDeclaration}s. */
2017-09-28 13:08:25 +02:00
export class VariableStatement extends Statement {
kind = NodeKind.VARIABLE;
2017-12-18 03:46:36 +01:00
/** Array of decorators. */
decorators: DecoratorNode[] | null;
2017-12-18 03:46:36 +01:00
/** Array of member declarations. */
2017-10-02 12:52:15 +02:00
declarations: VariableDeclaration[];
2017-09-28 13:08:25 +02:00
}
/** Represents a void statement dropping an expression's value. */
export class VoidStatement extends Statement {
kind = NodeKind.VOID;
/** Expression being dropped. */
expression: Expression;
}
2017-12-18 03:46:36 +01:00
/** Represents a `while` statement. */
2017-09-28 13:08:25 +02:00
export class WhileStatement extends Statement {
kind = NodeKind.WHILE;
2017-12-18 03:46:36 +01:00
/** Condition expression. */
2017-09-28 13:08:25 +02:00
condition: Expression;
2017-12-18 03:46:36 +01:00
/** Statement being looped over. */
2017-09-28 13:08:25 +02:00
statement: Statement;
}
/** Tests if a specific decorator is present within the specified decorators. */
export function hasDecorator(name: string, decorators: DecoratorNode[] | null): bool {
2018-02-25 00:13:39 +01:00
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
let expression = decorators[i].name;
2018-02-25 00:13:39 +01:00
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).text == name) {
return true;
2018-02-25 00:13:39 +01:00
}
2017-12-16 02:27:39 +01:00
}
2018-02-25 00:13:39 +01:00
}
return false;
2017-12-16 02:27:39 +01:00
}
2017-12-18 03:46:36 +01:00
/** Mangles a declaration's name to an internal name. */
2018-02-25 00:13:39 +01:00
export function mangleInternalName(declaration: DeclarationStatement, asGlobal: bool = false): string {
var name = declaration.name.text;
var parent = declaration.parent;
2018-02-25 00:13:39 +01:00
if (!parent) return name;
if (
declaration.kind == NodeKind.VARIABLEDECLARATION &&
parent.kind == NodeKind.VARIABLE
) { // skip over
if (!(parent = parent.parent)) return name;
}
if (parent.kind == NodeKind.CLASSDECLARATION) {
return mangleInternalName(<ClassDeclaration>parent, asGlobal) + (
declaration.is(CommonFlags.STATIC)
2018-02-25 00:13:39 +01:00
? STATIC_DELIMITER
: INSTANCE_DELIMITER
) + name;
2018-02-25 00:13:39 +01:00
}
if (
parent.kind == NodeKind.NAMESPACEDECLARATION ||
parent.kind == NodeKind.ENUMDECLARATION
) {
return mangleInternalName(<DeclarationStatement>parent, asGlobal) +
STATIC_DELIMITER + name;
}
return asGlobal
? name
: declaration.range.source.internalPath + PATH_DELIMITER + name;
}
/** Mangles an external to an internal path. */
2018-02-25 00:13:39 +01:00
export function mangleInternalPath(path: string): string {
if (path.endsWith(".ts")) path = path.substring(0, path.length - 3);
return path;
}
2018-02-25 00:13:39 +01:00
// Helpers
/** Sets the parent node on an array of nodes. */
2018-02-25 00:13:39 +01:00
function setParent(nodes: Node[], parent: Node): void {
for (let i = 0, k = nodes.length; i < k; ++i) {
nodes[i].parent = parent;
2018-02-25 00:13:39 +01:00
}
}
/** Sets the parent node on an array of nullable nodes. */
function setParentIfNotNull(nodes: (Node | null)[], parent: Node): void {
for (let i = 0, k = nodes.length; i < k; ++i) {
let node = nodes[i];
2018-02-25 00:13:39 +01:00
if (node) node.parent = parent;
}
}