UNPKG

json-as

Version:

The only JSON library you'll need for AssemblyScript. SIMD enabled

1,376 lines (1,293 loc) 40 kB
// Taken from https://github.com/as-pect/visitor-as/blob/master/src/astBuilder.ts // tslint:disable: as-internal-case import { CommonFlags, TypeNode, Node, NodeKind, Source, NamedTypeNode, FunctionTypeNode, TypeParameterNode, IdentifierExpression, CallExpression, ClassExpression, ElementAccessExpression, FunctionExpression, InstanceOfExpression, LiteralExpression, NewExpression, ParenthesizedExpression, PropertyAccessExpression, TernaryExpression, UnaryPostfixExpression, UnaryPrefixExpression, BlockStatement, BreakStatement, ContinueStatement, DoStatement, EmptyStatement, ExportStatement, ExportDefaultStatement, ExportImportStatement, ExpressionStatement, ForStatement, IfStatement, ImportStatement, ReturnStatement, SwitchStatement, ThrowStatement, TryStatement, VariableStatement, WhileStatement, ClassDeclaration, EnumDeclaration, EnumValueDeclaration, FieldDeclaration, FunctionDeclaration, ImportDeclaration, InterfaceDeclaration, MethodDeclaration, NamespaceDeclaration, TypeDeclaration, VariableDeclaration, DecoratorNode, ExportMember, ParameterNode, SwitchCase, TypeName, ArrayLiteralExpression, Expression, ObjectLiteralExpression, AssertionKind, LiteralKind, FloatLiteralExpression, StringLiteralExpression, RegexpLiteralExpression, UnaryExpression, ArrowKind, ParameterKind, DeclarationStatement, AssertionExpression, BinaryExpression, CommaExpression, IntegerLiteralExpression, isTypeOmitted, operatorTokenToString, ForOfStatement, IndexSignatureNode, TemplateLiteralExpression, util, FalseExpression, NullExpression, TrueExpression } from "assemblyscript/dist/assemblyscript.js"; import { Visitor } from "./visitor.js"; import { ThisExpression } from "types:assemblyscript/src/ast"; function assert<T>(isTruish: T, message: string = "assertion error"): T { if (!isTruish) throw new Error(message); return isTruish; } /** An AST builder. */ export class ASTBuilder extends Visitor { /** Rebuilds the textual source from the specified AST, as far as possible. */ static build(node: Node): string { var builder = new ASTBuilder(); builder.visitNode(node); return builder.finish(); } private sb: string[] = []; private indentLevel: number = 0; visitNode(node: Node) { return this.visit(node); } visitSource(source: Source): void { var statements = source.statements; for (let i = 0, k = statements.length; i < k; ++i) { this.visitNodeAndTerminate(statements[i]); } } // types visitTypeNode(node: TypeNode): void { switch (node.kind) { case NodeKind.NamedType: { this.visitNamedTypeNode(<NamedTypeNode>node); break; } case NodeKind.FunctionType: { this.visitFunctionTypeNode(<FunctionTypeNode>node); break; } default: assert(false); } } visitThisExpression(node: ThisExpression, ref?: Node | null): void { this.sb.push("this"); } visitTypeName(node: TypeName): void { this.visitIdentifierExpression(node.identifier); var sb = this.sb; var current = node.next; while (current) { sb.push("."); this.visitIdentifierExpression(current.identifier); current = current.next; } } visitNamedTypeNode(node: NamedTypeNode): void { this.visitTypeName(node.name); var typeArguments = node.typeArguments; if (typeArguments) { let numTypeArguments = typeArguments.length; let sb = this.sb; if (numTypeArguments) { sb.push("<"); this.visitTypeNode(typeArguments[0]); for (let i = 1; i < numTypeArguments; ++i) { sb.push(", "); this.visitTypeNode(typeArguments[i]); } sb.push(">"); } if (node.isNullable) sb.push(" | null"); } } visitFunctionTypeNode(node: FunctionTypeNode): void { var isNullable = node.isNullable; var sb = this.sb; sb.push(isNullable ? "((" : "("); var explicitThisType = node.explicitThisType; if (explicitThisType) { sb.push("this: "); this.visitTypeNode(explicitThisType); } var parameters = node.parameters; var numParameters = parameters.length; if (numParameters) { if (explicitThisType) sb.push(", "); this.serializeParameter(parameters[0]); for (let i = 1; i < numParameters; ++i) { sb.push(", "); this.serializeParameter(parameters[i]); } } var returnType = node.returnType; if (returnType) { sb.push(") => "); this.visitTypeNode(returnType); } else { sb.push(") => void"); } if (isNullable) sb.push(") | null"); } visitTypeParameter(node: TypeParameterNode): void { this.visitIdentifierExpression(node.name); var extendsType = node.extendsType; if (extendsType) { this.sb.push(" extends "); this.visitTypeNode(extendsType); } var defaultType = node.defaultType; if (defaultType) { this.sb.push("="); this.visitTypeNode(defaultType); } } // expressions visitIdentifierExpression(node: IdentifierExpression): void { if (node.isQuoted) this.visitStringLiteral(node.text); else this.sb.push(node.text); } visitArrayLiteralExpression(node: ArrayLiteralExpression): void { var sb = this.sb; sb.push("["); var elements = node.elementExpressions; var numElements = elements.length; if (numElements) { let element = elements[0]; if (element) this.visitNode(element); for (let i = 1; i < numElements; ++i) { element = elements[i]; sb.push(", "); if (element) this.visitNode(element); } } sb.push("]"); } visitObjectLiteralExpression(node: ObjectLiteralExpression): void { var sb = this.sb; var names = node.names; var values = node.values; var numElements = names.length; assert(numElements == values.length); if (numElements) { sb.push("{\n"); util.indent(sb, ++this.indentLevel); this.visitNode(names[0]); sb.push(": "); this.visitNode(values[0]); for (let i = 1; i < numElements; ++i) { sb.push(",\n"); util.indent(sb, this.indentLevel); let name = names[i]; let value = values[i]; if (name == value) { this.visitNode(name); } else { this.visitNode(name); sb.push(": "); this.visitNode(value); } } sb.push("\n"); util.indent(sb, --this.indentLevel); sb.push("}"); } else { sb.push("{}"); } } visitAssertionExpression(node: AssertionExpression): void { var sb = this.sb; switch (node.assertionKind) { case AssertionKind.Prefix: { sb.push("<"); if (node.toType) this.visitTypeNode(node.toType); sb.push(">"); this.visitNode(node.expression); break; } case AssertionKind.As: { this.visitNode(node.expression); sb.push(" as "); if (node.toType) this.visitTypeNode(node.toType); break; } case AssertionKind.NonNull: { this.visitNode(node.expression); sb.push("!"); break; } case AssertionKind.Const: { this.visitNode(node.expression); sb.push(" as const"); break; } default: assert(false); } } visitBinaryExpression(node: BinaryExpression): void { var sb = this.sb; this.visitNode(node.left); sb.push(" "); sb.push(operatorTokenToString(node.operator)); sb.push(" "); this.visitNode(node.right); } visitCallExpression(node: CallExpression): void { this.visitNode(node.expression); this.visitArguments(node.typeArguments, node.args); } visitArguments(typeArguments: TypeNode[] | null, args: Expression[]): void { var sb = this.sb; if (typeArguments) { let numTypeArguments = typeArguments.length; if (numTypeArguments) { sb.push("<"); this.visitTypeNode(typeArguments[0]); for (let i = 1; i < numTypeArguments; ++i) { sb.push(", "); this.visitTypeNode(typeArguments[i]); } sb.push(">("); } } else { sb.push("("); } var numArgs = args.length; if (numArgs) { this.visitNode(args[0]); for (let i = 1; i < numArgs; ++i) { sb.push(", "); this.visitNode(args[i]); } } sb.push(")"); } visitClassExpression(node: ClassExpression): void { var declaration = node.declaration; this.visitClassDeclaration(declaration); } visitCommaExpression(node: CommaExpression): void { var expressions = node.expressions; var numExpressions = expressions.length; this.visitNode(expressions[0]); var sb = this.sb; for (let i = 1; i < numExpressions; ++i) { sb.push(","); this.visitNode(expressions[i]); } } visitElementAccessExpression(node: ElementAccessExpression): void { var sb = this.sb; this.visitNode(node.expression); sb.push("["); this.visitNode(node.elementExpression); sb.push("]"); } visitFunctionExpression(node: FunctionExpression): void { var declaration = node.declaration; if (!declaration.arrowKind) { if (declaration.name.text.length) { this.sb.push("function "); } else { this.sb.push("function"); } } else { assert(declaration.name.text.length == 0); } this.visitFunctionCommon(declaration); } visitLiteralExpression(node: LiteralExpression): void { switch (node.literalKind) { case LiteralKind.Float: { this.visitFloatLiteralExpression(<FloatLiteralExpression>node); break; } case LiteralKind.Integer: { this.visitIntegerLiteralExpression(<IntegerLiteralExpression>node); break; } case LiteralKind.String: { this.visitStringLiteralExpression(<StringLiteralExpression>node); break; } case LiteralKind.Template: { this.visitTemplateLiteralExpression(<TemplateLiteralExpression>node); break; } case LiteralKind.RegExp: { this.visitRegexpLiteralExpression(<RegexpLiteralExpression>node); break; } case LiteralKind.Array: { this.visitArrayLiteralExpression(<ArrayLiteralExpression>node); break; } case LiteralKind.Object: { this.visitObjectLiteralExpression(<ObjectLiteralExpression>node); break; } default: { assert(false); break; } } } visitFloatLiteralExpression(node: FloatLiteralExpression): void { this.sb.push(node.value.toString()); } visitInstanceOfExpression(node: InstanceOfExpression): void { this.visitNode(node.expression); this.sb.push(" instanceof "); this.visitTypeNode(node.isType); } visitIntegerLiteralExpression(node: IntegerLiteralExpression): void { this.sb.push(i64_to_string(node.value)); } visitStringLiteral(str: string): void { var sb = this.sb; sb.push('"'); this.visitRawString(str, util.CharCode.DoubleQuote); sb.push('"'); } private visitRawString(str: string, quote: util.CharCode): void { var sb = this.sb; var off = 0; var i = 0; for (let k = str.length; i < k; ) { switch (str.charCodeAt(i)) { case util.CharCode.Null: { if (i > off) sb.push(str.substring(off, (off = i + 1))); sb.push("\\0"); off = ++i; break; } case util.CharCode.Backslash: { if (i > off) sb.push(str.substring(off, i)); off = ++i; sb.push("\\b"); break; } case util.CharCode.Tab: { if (i > off) sb.push(str.substring(off, i)); off = ++i; sb.push("\\t"); break; } case util.CharCode.LineFeed: { if (i > off) sb.push(str.substring(off, i)); off = ++i; sb.push("\\n"); break; } case util.CharCode.VerticalTab: { if (i > off) sb.push(str.substring(off, i)); off = ++i; sb.push("\\v"); break; } case util.CharCode.FormFeed: { if (i > off) sb.push(str.substring(off, i)); off = ++i; sb.push("\\f"); break; } case util.CharCode.CarriageReturn: { if (i > off) sb.push(str.substring(off, i)); sb.push("\\r"); off = ++i; break; } case util.CharCode.DoubleQuote: { if (quote == util.CharCode.DoubleQuote) { if (i > off) sb.push(str.substring(off, i)); sb.push('\\"'); off = ++i; } else { ++i; } break; } case util.CharCode.SingleQuote: { if (quote == util.CharCode.SingleQuote) { if (i > off) sb.push(str.substring(off, i)); sb.push("\\'"); off = ++i; } else { ++i; } break; } case util.CharCode.Backslash: { if (i > off) sb.push(str.substring(off, i)); sb.push("\\\\"); off = ++i; break; } case util.CharCode.Backtick: { if (quote == util.CharCode.Backtick) { if (i > off) sb.push(str.substring(off, i)); sb.push("\\`"); off = ++i; } else { ++i; } break; } default: { ++i; break; } } } if (i > off) sb.push(str.substring(off, i)); } visitStringLiteralExpression(node: StringLiteralExpression): void { this.visitStringLiteral(node.value); } visitTemplateLiteralExpression(node: TemplateLiteralExpression): void { var sb = this.sb; var tag = node.tag; var parts = node.parts; var expressions = node.expressions; if (tag) this.visitNode(tag); sb.push("`"); this.visitRawString(parts[0], util.CharCode.Backtick); assert(parts.length == expressions.length + 1); for (let i = 0, k = expressions.length; i < k; ++i) { sb.push("${"); this.visitNode(expressions[i]); sb.push("}"); this.visitRawString(parts[i + 1], util.CharCode.Backtick); } sb.push("`"); } visitRegexpLiteralExpression(node: RegexpLiteralExpression): void { var sb = this.sb; sb.push("/"); sb.push(node.pattern); sb.push("/"); sb.push(node.patternFlags); } visitNewExpression(node: NewExpression): void { this.sb.push("new "); this.visitTypeName(node.typeName); this.visitArguments(node.typeArguments, node.args); } visitParenthesizedExpression(node: ParenthesizedExpression): void { var sb = this.sb; sb.push("("); this.visitNode(node.expression); sb.push(")"); } visitPropertyAccessExpression(node: PropertyAccessExpression): void { this.visitNode(node.expression); this.sb.push("."); this.visitIdentifierExpression(node.property); } visitTernaryExpression(node: TernaryExpression): void { var sb = this.sb; this.visitNode(node.condition); sb.push(" ? "); this.visitNode(node.ifThen); sb.push(" : "); this.visitNode(node.ifElse); } visitUnaryExpression(node: UnaryExpression): void { switch (node.kind) { case NodeKind.UnaryPostfix: { this.visitUnaryPostfixExpression(<UnaryPostfixExpression>node); break; } case NodeKind.UnaryPrefix: { this.visitUnaryPrefixExpression(<UnaryPrefixExpression>node); break; } default: assert(false); } } visitUnaryPostfixExpression(node: UnaryPostfixExpression): void { this.visitNode(node.operand); this.sb.push(operatorTokenToString(node.operator)); } visitUnaryPrefixExpression(node: UnaryPrefixExpression): void { this.sb.push(operatorTokenToString(node.operator)); this.visitNode(node.operand); } // statements visitNodeAndTerminate(node: Node): void { this.visitNode(node); var sb = this.sb; if ( !sb.length || // leading EmptyStatement node.kind == NodeKind.Variable || // potentially assigns a FunctionExpression node.kind == NodeKind.Expression // potentially assigns a FunctionExpression ) { sb.push(";\n"); } else { let last = sb[sb.length - 1]; let lastCharPos = last.length - 1; if (lastCharPos >= 0 && (last.charCodeAt(lastCharPos) == util.CharCode.CloseBrace || last.charCodeAt(lastCharPos) == util.CharCode.Semicolon)) { sb.push("\n"); } else { sb.push(";\n"); } } } visitBlockStatement(node: BlockStatement): void { var sb = this.sb; var statements = node.statements; var numStatements = statements.length; if (numStatements) { sb.push("{\n"); let indentLevel = ++this.indentLevel; for (let i = 0; i < numStatements; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(statements[i]); } util.indent(sb, --this.indentLevel); sb.push("}"); } else { sb.push("{}"); } } visitBreakStatement(node: BreakStatement): void { var label = node.label; if (label) { this.sb.push("break "); this.visitIdentifierExpression(label); } else { this.sb.push("break"); } } visitContinueStatement(node: ContinueStatement): void { var label = node.label; if (label) { this.sb.push("continue "); this.visitIdentifierExpression(label); } else { this.sb.push("continue"); } } visitClassDeclaration(node: ClassDeclaration, isDefault = false): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } var sb = this.sb; if (isDefault) { sb.push("export default "); } else { this.serializeExternalModifiers(node); } if (node.is(CommonFlags.Abstract)) sb.push("abstract "); if (node.name.text.length) { sb.push("class "); this.visitIdentifierExpression(node.name); } else { sb.push("class"); } var typeParameters = node.typeParameters; if (typeParameters != null && typeParameters.length > 0) { sb.push("<"); this.visitTypeParameter(typeParameters[0]); for (let i = 1, k = typeParameters.length; i < k; ++i) { sb.push(", "); this.visitTypeParameter(typeParameters[i]); } sb.push(">"); } var extendsType = node.extendsType; if (extendsType) { sb.push(" extends "); this.visitTypeNode(extendsType); } var implementsTypes = node.implementsTypes; if (implementsTypes) { let numImplementsTypes = implementsTypes.length; if (numImplementsTypes) { sb.push(" implements "); this.visitTypeNode(implementsTypes[0]); for (let i = 1; i < numImplementsTypes; ++i) { sb.push(", "); this.visitTypeNode(implementsTypes[i]); } } } var indexSignature = node.indexSignature; var members = node.members; var numMembers = members.length; if (indexSignature !== null || numMembers) { sb.push(" {\n"); let indentLevel = ++this.indentLevel; if (indexSignature) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(indexSignature); } for (let i = 0, k = members.length; i < k; ++i) { let member = members[i]; if (member.kind != NodeKind.FieldDeclaration || (<FieldDeclaration>member).parameterIndex < 0) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(member); } } util.indent(sb, --this.indentLevel); sb.push("}"); } else { sb.push(" {}"); } } visitDoStatement(node: DoStatement): void { var sb = this.sb; sb.push("do "); this.visitNode(node.body); if (node.body.kind == NodeKind.Block) { sb.push(" while ("); } else { util.indent(sb, this.indentLevel); sb.push("while ("); } this.visitNode(node.condition); sb.push(")"); } visitEmptyStatement(node: EmptyStatement): void { /* nop */ } visitEnumDeclaration(node: EnumDeclaration, isDefault = false): void { var sb = this.sb; if (isDefault) { sb.push("export default "); } else { this.serializeExternalModifiers(node); } if (node.is(CommonFlags.Const)) sb.push("const "); sb.push("enum "); this.visitIdentifierExpression(node.name); var values = node.values; var numValues = values.length; if (numValues) { sb.push(" {\n"); let indentLevel = ++this.indentLevel; util.indent(sb, indentLevel); this.visitEnumValueDeclaration(node.values[0]); for (let i = 1; i < numValues; ++i) { sb.push(",\n"); util.indent(sb, indentLevel); this.visitEnumValueDeclaration(node.values[i]); } sb.push("\n"); util.indent(sb, --this.indentLevel); sb.push("}"); } else { sb.push(" {}"); } } visitEnumValueDeclaration(node: EnumValueDeclaration): void { this.visitIdentifierExpression(node.name); var initializer = node.initializer; if (initializer) { this.sb.push(" = "); this.visitNode(initializer); } } visitExportImportStatement(node: ExportImportStatement): void { var sb = this.sb; sb.push("export import "); this.visitIdentifierExpression(node.externalName); sb.push(" = "); this.visitIdentifierExpression(node.name); } visitExportMember(node: ExportMember): void { this.visitIdentifierExpression(node.localName); if (node.exportedName.text != node.localName.text) { this.sb.push(" as "); this.visitIdentifierExpression(node.exportedName); } } visitExportStatement(node: ExportStatement): void { var sb = this.sb; if (node.isDeclare) { sb.push("declare "); } var members = node.members; if (members == null) { sb.push("export *"); } else if (members.length > 0) { let numMembers = members.length; sb.push("export {\n"); let indentLevel = ++this.indentLevel; util.indent(sb, indentLevel); this.visitExportMember(members[0]); for (let i = 1; i < numMembers; ++i) { sb.push(",\n"); util.indent(sb, indentLevel); this.visitExportMember(members[i]); } --this.indentLevel; sb.push("\n}"); } else { sb.push("export {}"); } var path = node.path; if (path) { sb.push(" from "); this.visitStringLiteralExpression(path); } sb.push(";"); } visitExportDefaultStatement(node: ExportDefaultStatement): void { var declaration = node.declaration; switch (declaration.kind) { case NodeKind.EnumDeclaration: { this.visitEnumDeclaration(<EnumDeclaration>declaration, true); break; } case NodeKind.FunctionDeclaration: { this.visitFunctionDeclaration(<FunctionDeclaration>declaration, true); break; } case NodeKind.ClassDeclaration: { this.visitClassDeclaration(<ClassDeclaration>declaration, true); break; } case NodeKind.InterfaceDeclaration: { this.visitInterfaceDeclaration(<InterfaceDeclaration>declaration, true); break; } case NodeKind.NamespaceDeclaration: { this.visitNamespaceDeclaration(<NamespaceDeclaration>declaration, true); break; } default: assert(false); } } visitExpressionStatement(node: ExpressionStatement): void { this.visitNode(node.expression); } visitFieldDeclaration(node: FieldDeclaration): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } this.serializeAccessModifiers(node); this.visitIdentifierExpression(node.name); var sb = this.sb; if (node.flags & CommonFlags.DefinitelyAssigned) { sb.push("!"); } var type = node.type; if (type) { sb.push(": "); this.visitTypeNode(type); } var initializer = node.initializer; if (initializer) { sb.push(" = "); this.visitNode(initializer); } } visitForStatement(node: ForStatement): void { var sb = this.sb; sb.push("for ("); var initializer = node.initializer; if (initializer) { this.visitNode(initializer); } var condition = node.condition; if (condition) { sb.push("; "); this.visitNode(condition); } else { sb.push(";"); } var incrementor = node.incrementor; if (incrementor) { sb.push("; "); this.visitNode(incrementor); } else { sb.push(";"); } sb.push(") "); this.visitNode(node.body); } visitForOfStatement(node: ForOfStatement): void { var sb = this.sb; sb.push("for ("); this.visitNode(node.variable); sb.push(" of "); this.visitNode(node.iterable); sb.push(") "); this.visitNode(node.body); } visitFunctionDeclaration(node: FunctionDeclaration, isDefault = false): void { var sb = this.sb; var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } if (isDefault) { sb.push("export default "); } else { this.serializeExternalModifiers(node); this.serializeAccessModifiers(node); } if (node.name.text.length) { sb.push("function "); } else { sb.push("function"); } this.visitFunctionCommon(node); } visitFunctionCommon(node: FunctionDeclaration): void { var sb = this.sb; this.visitIdentifierExpression(node.name); var signature = node.signature; var typeParameters = node.typeParameters; if (typeParameters) { let numTypeParameters = typeParameters.length; if (numTypeParameters) { sb.push("<"); this.visitTypeParameter(typeParameters[0]); for (let i = 1; i < numTypeParameters; ++i) { sb.push(", "); this.visitTypeParameter(typeParameters[i]); } sb.push(">"); } } if (node.arrowKind == ArrowKind.Single) { let parameters = signature.parameters; assert(parameters.length == 1); assert(!signature.explicitThisType); this.serializeParameter(parameters[0]); } else { sb.push("("); let parameters = signature.parameters; let numParameters = parameters.length; let explicitThisType = signature.explicitThisType; if (explicitThisType) { sb.push("this: "); this.visitTypeNode(explicitThisType); } if (numParameters) { if (explicitThisType) sb.push(", "); this.serializeParameter(parameters[0]); for (let i = 1; i < numParameters; ++i) { sb.push(", "); this.serializeParameter(parameters[i]); } } } var body = node.body; var returnType = signature.returnType; if (node.arrowKind) { if (body) { if (node.arrowKind == ArrowKind.Single) { assert(isTypeOmitted(returnType)); } else { if (isTypeOmitted(returnType)) { sb.push(")"); } else { sb.push("): "); this.visitTypeNode(returnType); } } sb.push(" => "); this.visitNode(body); } else { assert(!isTypeOmitted(returnType)); sb.push(" => "); this.visitTypeNode(returnType); } } else { if (!isTypeOmitted(returnType) && !node.isAny(CommonFlags.Constructor | CommonFlags.Set)) { sb.push("): "); this.visitTypeNode(returnType); } else { sb.push(")"); } if (body) { sb.push(" "); this.visitNode(body); } } } visitIfStatement(node: IfStatement): void { var sb = this.sb; sb.push("if ("); this.visitNode(node.condition); sb.push(") "); var ifTrue = node.ifTrue; this.visitNode(ifTrue); if (ifTrue.kind != NodeKind.Block) { sb.push(";\n"); } var ifFalse = node.ifFalse; if (ifFalse) { if (ifTrue.kind == NodeKind.Block) { sb.push(" else "); } else { sb.push("else "); } this.visitNode(ifFalse); } } visitImportDeclaration(node: ImportDeclaration): void { var externalName = node.foreignName; var name = node.name; this.visitIdentifierExpression(externalName); if (externalName.text != name.text) { this.sb.push(" as "); this.visitIdentifierExpression(name); } } visitImportStatement(node: ImportStatement): void { var sb = this.sb; sb.push("import "); var declarations = node.declarations; var namespaceName = node.namespaceName; if (declarations) { let numDeclarations = declarations.length; if (numDeclarations) { sb.push("{\n"); let indentLevel = ++this.indentLevel; util.indent(sb, indentLevel); this.visitImportDeclaration(declarations[0]); for (let i = 1; i < numDeclarations; ++i) { sb.push(",\n"); util.indent(sb, indentLevel); this.visitImportDeclaration(declarations[i]); } --this.indentLevel; sb.push("\n} from "); } else { sb.push("{} from "); } } else if (namespaceName) { sb.push("* as "); this.visitIdentifierExpression(namespaceName); sb.push(" from "); } this.visitStringLiteralExpression(node.path); } visitIndexSignature(node: IndexSignatureNode): void { var sb = this.sb; sb.push("[key: "); this.visitTypeNode(node.keyType); sb.push("]: "); this.visitTypeNode(node.valueType); } visitInterfaceDeclaration(node: InterfaceDeclaration, isDefault = false): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } var sb = this.sb; if (isDefault) { sb.push("export default "); } else { this.serializeExternalModifiers(node); } sb.push("interface "); this.visitIdentifierExpression(node.name); var typeParameters = node.typeParameters; if (typeParameters != null && typeParameters.length > 0) { sb.push("<"); this.visitTypeParameter(typeParameters[0]); for (let i = 1, k = typeParameters.length; i < k; ++i) { sb.push(", "); this.visitTypeParameter(typeParameters[i]); } sb.push(">"); } var extendsType = node.extendsType; if (extendsType) { sb.push(" extends "); this.visitTypeNode(extendsType); } // must not have implementsTypes sb.push(" {\n"); var indentLevel = ++this.indentLevel; var members = node.members; for (let i = 0, k = members.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(members[i]); } --this.indentLevel; sb.push("}"); } visitMethodDeclaration(node: MethodDeclaration): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } this.serializeAccessModifiers(node); if (node.is(CommonFlags.Get)) { this.sb.push("get "); } else if (node.is(CommonFlags.Set)) { this.sb.push("set "); } this.visitFunctionCommon(node); } visitNamespaceDeclaration(node: NamespaceDeclaration, isDefault = false): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } var sb = this.sb; if (isDefault) { sb.push("export default "); } else { this.serializeExternalModifiers(node); } sb.push("namespace "); this.visitIdentifierExpression(node.name); var members = node.members; var numMembers = members.length; if (numMembers) { sb.push(" {\n"); let indentLevel = ++this.indentLevel; for (let i = 0, k = members.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(members[i]); } util.indent(sb, --this.indentLevel); sb.push("}"); } else { sb.push(" {}"); } } visitReturnStatement(node: ReturnStatement): void { var value = node.value; if (value) { this.sb.push("return "); this.visitNode(value); } else { this.sb.push("return"); } } visitTrueExpression(node: TrueExpression): void { this.sb.push("true"); } visitFalseExpression(node: FalseExpression): void { this.sb.push("false"); } visitNullExpression(node: NullExpression): void { this.sb.push("null"); } visitSwitchCase(node: SwitchCase): void { var sb = this.sb; var label = node.label; if (label) { sb.push("case "); this.visitNode(label); sb.push(":\n"); } else { sb.push("default:\n"); } var statements = node.statements; var numStatements = statements.length; if (numStatements) { let indentLevel = ++this.indentLevel; util.indent(sb, indentLevel); this.visitNodeAndTerminate(statements[0]); for (let i = 1; i < numStatements; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(statements[i]); } --this.indentLevel; } } visitSwitchStatement(node: SwitchStatement): void { var sb = this.sb; sb.push("switch ("); this.visitNode(node.condition); sb.push(") {\n"); var indentLevel = ++this.indentLevel; var cases = node.cases; for (let i = 0, k = cases.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitSwitchCase(cases[i]); sb.push("\n"); } --this.indentLevel; sb.push("}"); } visitThrowStatement(node: ThrowStatement): void { this.sb.push("throw "); this.visitNode(node.value); } visitTryStatement(node: TryStatement): void { var sb = this.sb; sb.push("try {\n"); var indentLevel = ++this.indentLevel; var statements = node.bodyStatements; for (let i = 0, k = statements.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(statements[i]); } var catchVariable = node.catchVariable; if (catchVariable) { util.indent(sb, indentLevel - 1); sb.push("} catch ("); this.visitIdentifierExpression(catchVariable); sb.push(") {\n"); let catchStatements = node.catchStatements; if (catchStatements) { for (let i = 0, k = catchStatements.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(catchStatements[i]); } } } var finallyStatements = node.finallyStatements; if (finallyStatements) { util.indent(sb, indentLevel - 1); sb.push("} finally {\n"); for (let i = 0, k = finallyStatements.length; i < k; ++i) { util.indent(sb, indentLevel); this.visitNodeAndTerminate(finallyStatements[i]); } } util.indent(sb, indentLevel - 1); sb.push("}"); } visitTypeDeclaration(node: TypeDeclaration): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } var sb = this.sb; this.serializeExternalModifiers(node); sb.push("type "); this.visitIdentifierExpression(node.name); var typeParameters = node.typeParameters; if (typeParameters) { let numTypeParameters = typeParameters.length; if (numTypeParameters) { sb.push("<"); for (let i = 0; i < numTypeParameters; ++i) { this.visitTypeParameter(typeParameters[i]); } sb.push(">"); } } sb.push(" = "); this.visitTypeNode(node.type); } visitVariableDeclaration(node: VariableDeclaration): void { this.visitIdentifierExpression(node.name); var type = node.type; var sb = this.sb; if (node.flags & CommonFlags.DefinitelyAssigned) { sb.push("!"); } if (type) { sb.push(": "); this.visitTypeNode(type); } var initializer = node.initializer; if (initializer) { sb.push(" = "); this.visitNode(initializer); } } visitVariableStatement(node: VariableStatement): void { var decorators = node.decorators; if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { this.serializeDecorator(decorators[i]); } } var sb = this.sb; var declarations = node.declarations; var numDeclarations = declarations.length; var firstDeclaration = declarations[0]; this.serializeExternalModifiers(firstDeclaration); sb.push(firstDeclaration.is(CommonFlags.Const) ? "const " : firstDeclaration.is(CommonFlags.Let) ? "let " : "var "); this.visitVariableDeclaration(node.declarations[0]); for (let i = 1; i < numDeclarations; ++i) { sb.push(", "); this.visitVariableDeclaration(node.declarations[i]); } } visitWhileStatement(node: WhileStatement): void { var sb = this.sb; sb.push("while ("); this.visitNode(node.condition); var statement = node.body; if (statement.kind == NodeKind.Empty) { sb.push(")"); } else { sb.push(") "); this.visitNode(node.body); } } // other serializeDecorator(node: DecoratorNode): void { var sb = this.sb; sb.push("@"); this.visitNode(node.name); var args = node.args; if (args) { sb.push("("); let numArgs = args.length; if (numArgs) { this.visitNode(args[0]); for (let i = 1; i < numArgs; ++i) { sb.push(", "); this.visitNode(args[i]); } } sb.push(")\n"); } else { sb.push("\n"); } util.indent(sb, this.indentLevel); } serializeParameter(node: ParameterNode): void { var sb = this.sb; var kind = node.parameterKind; var implicitFieldDeclaration = node.implicitFieldDeclaration; if (implicitFieldDeclaration) { this.serializeAccessModifiers(implicitFieldDeclaration); } if (kind == ParameterKind.Rest) { sb.push("..."); } this.visitIdentifierExpression(node.name); var type = node.type; var initializer = node.initializer; if (type) { if (kind == ParameterKind.Optional && !initializer) sb.push("?"); if (!isTypeOmitted(type)) { sb.push(": "); this.visitTypeNode(type); } } if (initializer) { sb.push(" = "); this.visitNode(initializer); } } serializeExternalModifiers(node: DeclarationStatement): void { var sb = this.sb; if (node.is(CommonFlags.Export)) { sb.push("export "); } else if (node.is(CommonFlags.Import)) { sb.push("import "); } else if (node.is(CommonFlags.Declare)) { sb.push("declare "); } } serializeAccessModifiers(node: DeclarationStatement): void { var sb = this.sb; if (node.is(CommonFlags.Public)) { sb.push("public "); } else if (node.is(CommonFlags.Private)) { sb.push("private "); } else if (node.is(CommonFlags.Protected)) { sb.push("protected "); } if (node.is(CommonFlags.Static)) { sb.push("static "); } else if (node.is(CommonFlags.Abstract)) { sb.push("abstract "); } if (node.is(CommonFlags.Readonly)) { sb.push("readonly "); } } finish(): string { var ret = this.sb.join(""); this.sb = []; return ret; } }