diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..ab7248f9 --- /dev/null +++ b/src/README.md @@ -0,0 +1 @@ +Portable compiler sources that compile to both JavaScript using `tsc` and, eventually, WebAssembly using `asc`. diff --git a/src/ast.ts b/src/ast.ts index 383d49d1..cec50177 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -10,10 +10,6 @@ import { Range } from "./tokenizer"; -import { - CharCode -} from "./util/charcode"; - import { I64 } from "./util/i64"; @@ -23,7 +19,10 @@ import { resolve as resolvePath } from "./util/path"; -export { Range } from "./tokenizer"; +export { + Token, + Range +}; /** Indicates the kind of a node. */ export enum NodeKind { @@ -58,39 +57,41 @@ export enum NodeKind { // statements BLOCK, BREAK, - CASE, - CLASS, // is also declaration CONTINUE, DO, EMPTY, - ENUM, // is also declaration - ENUMVALUE, // is also declaration EXPORT, EXPORTIMPORT, - EXPORTMEMBER, EXPRESSION, - INTERFACE, FOR, - FUNCTION, // is also declaration IF, - IMPORT, // wraps declarations - IMPORTDECLARATION, - METHOD, // is also declaration - NAMESPACE, // is also declaration - FIELD, + IMPORT, RETURN, SWITCH, THROW, TRY, - TYPEDECLARATION, - VARIABLE, // wraps declarations - VARIABLEDECLARATION, + VARIABLE, WHILE, + // declaration statements + CLASSDECLARATION, + ENUMDECLARATION, + ENUMVALUEDECLARATION, + FIELDDECLARATION, + FUNCTIONDECLARATION, + IMPORTDECLARATION, + INTERFACEDECLARATION, + METHODDECLARATION, + NAMESPACEDECLARATION, + TYPEDECLARATION, + VARIABLEDECLARATION, + // other DECORATOR, + EXPORTMEMBER, MODIFIER, - PARAMETER + PARAMETER, + SWITCHCASE } /** Base class of all nodes. */ @@ -103,9 +104,6 @@ export abstract class Node { /** Parent node. */ parent: Node | null = null; - /** Serializes this node to its TypeScript representation. Note that formatting is lost and long integers become hex literals. */ - abstract serialize(sb: string[]): void; - // types static createType(identifier: IdentifierExpression, typeArguments: TypeNode[], isNullable: bool, range: Range): TypeNode { @@ -447,7 +445,6 @@ export abstract class Node { return elem; } - /** Creates an expression statement. */ static createExpressionStatement(expression: Expression): ExpressionStatement { var stmt = new ExpressionStatement(); stmt.range = expression.range; @@ -741,21 +738,6 @@ export class TypeNode extends Node { typeArguments: TypeNode[]; /** Whether nullable or not. */ isNullable: bool; - - serialize(sb: string[]): void { - this.identifier.serialize(sb); - if (this.typeArguments.length) { - sb.push("<"); - for (var i = 0, k = this.typeArguments.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.typeArguments[i].serialize(sb); - } - sb.push(">"); - } - if (this.isNullable) - sb.push(" | null"); - } } /** Represents a type parameter. */ @@ -767,14 +749,6 @@ export class TypeParameter extends Node { identifier: IdentifierExpression; /** Extended type reference, if any. */ extendsType: TypeNode | null; - - serialize(sb: string[]): void { - this.identifier.serialize(sb); - if (this.extendsType) { - sb.push(" extends "); - (this.extendsType).serialize(sb); - } - } } // expressions @@ -784,15 +758,10 @@ export abstract class Expression extends Node { } /** Represents an identifier expression. */ export class IdentifierExpression extends Expression { - kind = NodeKind.IDENTIFIER; /** Textual name. */ name: string; - - serialize(sb: string[]): void { - sb.push(this.name); - } } /** Indicates the kind of a literal. */ @@ -807,7 +776,6 @@ export const enum LiteralKind { /** Base class of all literal expressions. */ export abstract class LiteralExpression extends Expression { - kind = NodeKind.LITERAL; /** Specific literal kind. */ @@ -816,23 +784,10 @@ export abstract class LiteralExpression extends Expression { /** Represents an `[]` literal expression. */ export class ArrayLiteralExpression extends LiteralExpression { - - // kind = NodeKind.LITERAL literalKind = LiteralKind.ARRAY; /** Nested element expressions. */ elementExpressions: (Expression | null)[]; - - serialize(sb: string[]): void { - sb.push("["); - for (var i = 0, k = this.elementExpressions.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - if (this.elementExpressions[i]) - (this.elementExpressions[i]).serialize(sb); - } - sb.push("]"); - } } /** Indicates the kind of an assertion. */ @@ -843,7 +798,6 @@ export const enum AssertionKind { /** Represents an assertion expression. */ export class AssertionExpression extends Expression { - kind = NodeKind.ASSERTION; /** Specific kind of this assertion. */ @@ -852,24 +806,10 @@ export class AssertionExpression extends Expression { expression: Expression; /** Target type. */ toType: TypeNode; - - serialize(sb: string[]): void { - if (this.assertionKind == AssertionKind.PREFIX) { - sb.push("<"); - this.toType.serialize(sb); - sb.push(">"); - this.expression.serialize(sb); - } else { - this.expression.serialize(sb); - sb.push(" as "); - this.toType.serialize(sb); - } - } } /** Represents a binary expression. */ export class BinaryExpression extends Expression { - kind = NodeKind.BINARY; /** Operator token. */ @@ -878,19 +818,10 @@ export class BinaryExpression extends Expression { left: Expression; /** Right-hand side expression. */ right: Expression; - - serialize(sb: string[]): void { - this.left.serialize(sb); - sb.push(" "); - sb.push(Token.operatorToString(this.operator)); - sb.push(" "); - this.right.serialize(sb); - } } /** Represents a call expression. */ export class CallExpression extends Expression { - kind = NodeKind.CALL; /** Called expression. Usually an identifier or property access expression. */ @@ -899,107 +830,51 @@ export class CallExpression extends Expression { typeArguments: TypeNode[] | null; /** Provided arguments. */ arguments: Expression[]; - - serialize(sb: string[]): void { - this.expression.serialize(sb); - var k: i32; - if (this.typeArguments && (k = this.typeArguments.length)) { - sb.push("<"); - for (var i = 0; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.typeArguments[i].serialize(sb); - } - sb.push(">("); - } else - sb.push("("); - for (i = 0, k = this.arguments.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.arguments[i].serialize(sb); - } - sb.push(")"); - } } /** Represents a comma expression composed of multiple sequential expressions. */ export class CommaExpression extends Expression { - kind = NodeKind.COMMA; /** Sequential expressions. */ expressions: Expression[]; - - serialize(sb: string[]): void { - this.expressions[0].serialize(sb); - for (var i = 1, k = this.expressions.length; i < k; ++i) { - sb.push(","); - this.expressions[i].serialize(sb); - } - } } /** Represents a `constructor` expression. */ export class ConstructorExpression extends IdentifierExpression { kind = NodeKind.CONSTRUCTOR; - name = "this"; + name = "constructor"; } /** Represents an element access expression, e.g., array access. */ export class ElementAccessExpression extends Expression { - kind = NodeKind.ELEMENTACCESS; /** Expression being accessed. */ expression: Expression; /** Element of the expression being accessed. */ elementExpression: Expression; - - serialize(sb: string[]): void { - this.expression.serialize(sb); - sb.push("["); - this.elementExpression.serialize(sb); - sb.push("]"); - } } /** Represents a float literal expression. */ export class FloatLiteralExpression extends LiteralExpression { - - // kind = NodeKind.LITERAL literalKind = LiteralKind.FLOAT; /** Float value. */ value: f64; - - serialize(sb: string[]): void { - sb.push(this.value.toString(10)); - } } /** Represents an integer literal expression. */ export class IntegerLiteralExpression extends LiteralExpression { - - // kind = NodeKind.LITERAL literalKind = LiteralKind.INTEGER; /** Integer value. */ value: I64; - - serialize(sb: string[]): void { - sb.push(this.value.toString()); - } } /** Represents a `new` expression. Like a call but with its own kind. */ export class NewExpression extends CallExpression { - kind = NodeKind.NEW; - - serialize(sb: string[]): void { - sb.push("new "); - super.serialize(sb); - } } /** Represents a `null` expression. */ @@ -1010,58 +885,34 @@ export class NullExpression extends IdentifierExpression { /** Represents a parenthesized expression. */ export class ParenthesizedExpression extends Expression { - kind = NodeKind.PARENTHESIZED; /** Expression in parenthesis. */ expression: Expression; - - serialize(sb: string[]): void { - sb.push("("); - this.expression.serialize(sb); - sb.push(")"); - } } /** Represents a property access expression. */ export class PropertyAccessExpression extends Expression { - kind = NodeKind.PROPERTYACCESS; /** Expression being accessed. */ expression: Expression; /** Property of the expression being accessed. */ property: IdentifierExpression; - - serialize(sb: string[]): void { - this.expression.serialize(sb); - sb.push("."); - this.property.serialize(sb); - } } /** Represents a regular expression literal expression. */ export class RegexpLiteralExpression extends LiteralExpression { - - // kind = NodeKind.LITERAL literalKind = LiteralKind.REGEXP; /** Regular expression pattern. */ pattern: string; /** Regular expression flags. */ patternFlags: string; - - serialize(sb: string[]): void { - sb.push("/"); - sb.push(this.pattern); - sb.push("/"); - sb.push(this.patternFlags); - } } /** Represents a ternary expression, i.e., short if notation. */ export class TernaryExpression extends Expression { - kind = NodeKind.TERNARY; /** Condition expression. */ @@ -1070,27 +921,14 @@ export class TernaryExpression extends Expression { ifThen: Expression; /** Expression executed when condition is `false`. */ ifElse: Expression; - - serialize(sb: string[]): void { - this.condition.serialize(sb); - sb.push(" ? "); - this.ifThen.serialize(sb); - sb.push(" : "); - this.ifElse.serialize(sb); - } } /** Represents a string literal expression. */ export class StringLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.STRING; /** String value without quotes. */ value: string; - - serialize(sb: string[]): void { - sb.push(stringToLiteral(this.value)); - } } /** Represents a `super` expression. */ @@ -1120,8 +958,6 @@ export class FalseExpression extends IdentifierExpression { /** Base class of all unary expressions. */ export abstract class UnaryExpression extends Expression { - // kind varies - /** Operator token. */ operator: Token; /** Operand expression. */ @@ -1130,28 +966,12 @@ export abstract class UnaryExpression extends Expression { /** Represents a unary postfix expression, e.g. a postfix increment. */ export class UnaryPostfixExpression extends UnaryExpression { - kind = NodeKind.UNARYPOSTFIX; - - serialize(sb: string[]): void { - this.operand.serialize(sb); - switch (this.operator) { - case Token.PLUS_PLUS: sb.push("++"); break; - case Token.MINUS_MINUS: sb.push("--"); break; - default: sb.push("INVALID"); break; - } - } } /** Represents a unary prefix expression, e.g. a negation. */ export class UnaryPrefixExpression extends UnaryExpression { - kind = NodeKind.UNARYPREFIX; - - serialize(sb: string[]): void { - sb.push(Token.operatorToString(this.operator)); - this.operand.serialize(sb); - } } // statements @@ -1184,7 +1004,6 @@ export enum SourceKind { /** A top-level source node. */ export class Source extends Node { - kind = NodeKind.SOURCE; parent = null; @@ -1219,23 +1038,11 @@ export class Source extends Node { get isEntry(): bool { return this.sourceKind == SourceKind.ENTRY; } /** Tests if this source is a stdlib file. */ get isStdlib(): bool { return this.sourceKind == SourceKind.STDLIB; } - - serialize(sb: string[]): void { - for (var i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) { - this.statements[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - } } /** Base class of all declaration statements. */ export abstract class DeclarationStatement extends Statement { - // kind varies - /** Simple name being declared. */ name: IdentifierExpression; /** Array of modifiers. */ @@ -1254,8 +1061,6 @@ export abstract class DeclarationStatement extends Statement { /** Base class of all variable-like declaration statements with a type and initializer. */ export abstract class VariableLikeDeclarationStatement extends DeclarationStatement { - // kind varies - /** Variable type. */ type: TypeNode | null; /** Variable initializer. */ @@ -1264,46 +1069,23 @@ export abstract class VariableLikeDeclarationStatement extends DeclarationStatem /** Represents a block statement. */ export class BlockStatement extends Statement { - kind = NodeKind.BLOCK; /** Contained statements. */ statements: Statement[]; - - serialize(sb: string[]): void { - sb.push("{\n"); - for (var i = 0, k = this.statements.length; i < k; ++i) { - this.statements[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - sb.push("}"); - } } /** Represents a `break` statement. */ export class BreakStatement extends Statement { - kind = NodeKind.BREAK; /** Target label, if applicable. */ label: IdentifierExpression | null; - - serialize(sb: string[]): void { - if (this.label) { - sb.push("break "); - (this.label).serialize(sb); - } else - sb.push("break"); - } } /** Represents a `class` declaration. */ export class ClassDeclaration extends DeclarationStatement { - - kind = NodeKind.CLASS; + kind = NodeKind.CLASSDECLARATION; /** Accepted type parameters. */ typeParameters: TypeParameter[]; @@ -1313,68 +1095,14 @@ export class ClassDeclaration extends DeclarationStatement { implementsTypes: TypeNode[]; /** Class member declarations. */ members: DeclarationStatement[]; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - sb.push("class "); - sb.push(this.name.name); - if (this.typeParameters.length) { - sb.push("<"); - for (i = 0, k = this.typeParameters.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.typeParameters[i].serialize(sb); - } - sb.push(">"); - } - if (this.extendsType) { - sb.push(" extends "); - this.extendsType.serialize(sb); - } - if (this.implementsTypes.length) { - sb.push(" implements "); - for (i = 0, k = this.implementsTypes.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.implementsTypes[i].serialize(sb); - } - } - sb.push(" {\n"); - for (i = 0, k = this.members.length; i < k; ++i) { - this.members[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - sb.push("}"); - } } /** Represents a `continue` statement. */ export class ContinueStatement extends Statement { - kind = NodeKind.CONTINUE; /** Target label, if applicable. */ label: IdentifierExpression | null; - - serialize(sb: string[]): void { - if (this.label) { - sb.push("continue "); - (this.label).serialize(sb); - } else - sb.push("continue"); - } } /** Built-in decorator kinds. */ @@ -1388,7 +1116,6 @@ export const enum DecoratorKind { /** Depresents a decorator. */ export class Decorator extends Statement { - kind = NodeKind.DECORATOR; /** Name expression. */ @@ -1397,137 +1124,63 @@ export class Decorator extends Statement { arguments: Expression[] | null; /** Built-in kind, if applicable. */ decoratorKind: DecoratorKind; - - serialize(sb: string[]): void { - sb.push("@"); - this.name.serialize(sb); - if (this.arguments) { - sb.push("("); - for (var i = 0, k = this.arguments.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.arguments[i].serialize(sb); - } - sb.push(")"); - } - } } /** Represents a `do` statement. */ export class DoStatement extends Statement { - kind = NodeKind.DO; /** Statement being looped over. */ statement: Statement; /** Condition when to repeat. */ condition: Expression; - - serialize(sb: string[]): void { - sb.push("do "); - this.statement.serialize(sb); - if (this.statement.kind == NodeKind.BLOCK) - sb.push(" while ("); - else - sb.push(";\nwhile ("); - this.condition.serialize(sb); - sb.push(")"); - } } /** Represents an empty statement, i.e., a semicolon terminating nothing. */ export class EmptyStatement extends Statement { - kind = NodeKind.EMPTY; - - serialize(sb: string[]): void {} } /** Represents an `enum` declaration. */ export class EnumDeclaration extends DeclarationStatement { - - kind = NodeKind.ENUM; + kind = NodeKind.ENUMDECLARATION; /** Enum value declarations. */ values: EnumValueDeclaration[]; - - serialize(sb: string[]): void { - if (this.modifiers) - for (var i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - sb.push("enum "); - this.name.serialize(sb); - sb.push(" {\n"); - for (i = 0, k = this.values.length; i < k; ++i) { - if (i > 0) - sb.push(",\n"); - this.values[i].serialize(sb); - } - sb.push("\n}"); - } } /** Represents a value of an `enum` declaration. */ export class EnumValueDeclaration extends DeclarationStatement { - - kind = NodeKind.ENUMVALUE; + kind = NodeKind.ENUMVALUEDECLARATION; modifiers = null; // name is inherited /** Value expression. */ value: Expression | null; - - serialize(sb: string[]): void { - this.name.serialize(sb); - if (this.value) { - sb.push(" = "); - (this.value).serialize(sb); - } - } } /** Represents an `export import` statement of an interface. */ export class ExportImportStatement extends Node { - kind = NodeKind.EXPORTIMPORT; /** Identifier being imported. */ identifier: IdentifierExpression; /** Identifier being exported. */ externalIdentifier: IdentifierExpression; - - serialize(sb: string[]): void { - sb.push("export import "); - this.externalIdentifier.serialize(sb); - sb.push(" = "); - this.identifier.serialize(sb); - } } /** Represents a member of an `export` statement. */ export class ExportMember extends Node { - kind = NodeKind.EXPORTMEMBER; /** Identifier being exported. */ identifier: IdentifierExpression; /** Identifier seen when imported again. */ externalIdentifier: IdentifierExpression; - - serialize(sb: string[]): void { - this.identifier.serialize(sb); - if (this.externalIdentifier.name != this.identifier.name) { - sb.push(" as "); - (this.externalIdentifier).serialize(sb); - } - } } /** Represents an `export` statement. */ export class ExportStatement extends Statement { - kind = NodeKind.EXPORT; /** Array of modifiers. */ @@ -1540,71 +1193,23 @@ export class ExportStatement extends Statement { normalizedPath: string | null; /** Mangled internal path being referenced, if `path` is set. */ internalPath: string | null; - - serialize(sb: string[]): void { - if (this.modifiers) - for (var i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - sb.push("export {\n"); - for (i = 0, k = this.members.length; i < k; ++i) { - if (i > 0) - sb.push(",\n"); - this.members[i].serialize(sb); - } - if (this.path) { - sb.push("\n} from "); - this.path.serialize(sb); - } else - sb.push("\n}"); - } } /** Represents an expression statement, i.e., an expression being used as a statement */ export class ExpressionStatement extends Statement { - kind = NodeKind.EXPRESSION; /** Expression being used as a statement.*/ expression: Expression; - - serialize(sb: string[]): void { - this.expression.serialize(sb); - } } /** Represents a field declaration within a `class`. */ export class FieldDeclaration extends VariableLikeDeclarationStatement { - - kind = NodeKind.FIELD; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - this.name.serialize(sb); - if (this.type) { - sb.push(": "); - (this.type).serialize(sb); - } - if (this.initializer) { - sb.push(" = "); - (this.initializer).serialize(sb); - } - } + kind = NodeKind.FIELDDECLARATION; } /** Represents a `for` statement. */ export class ForStatement extends Statement { - kind = NodeKind.FOR; /** Initializer statement, if present. Either a {@link VariableStatement} or {@link ExpressionStatement}. */ @@ -1615,30 +1220,11 @@ export class ForStatement extends Statement { incrementor: Expression | null; /** Statement being looped over. */ statement: Statement; - - serialize(sb: string[]): void { - sb.push("for ("); - if (this.initializer) - this.initializer.serialize(sb); - if (this.condition) { - sb.push("; "); - this.condition.serialize(sb); - } else - sb.push(";"); - if (this.incrementor) { - sb.push("; "); - this.incrementor.serialize(sb); - } else - sb.push(";"); - sb.push(") "); - this.statement.serialize(sb); - } } /** Represents a `function` declaration. */ export class FunctionDeclaration extends DeclarationStatement { - - kind = NodeKind.FUNCTION; + kind = NodeKind.FUNCTIONDECLARATION; /** Accepted type parameters. */ typeParameters: TypeParameter[]; @@ -1648,62 +1234,10 @@ export class FunctionDeclaration extends DeclarationStatement { returnType: TypeNode | null; /** Contained statements. */ statements: Statement[] | null; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - sb.push("function "); - this.serializeCommon(sb); - } - - protected serializeCommon(sb: string[]): void { - this.name.serialize(sb); - if (this.typeParameters.length) { - sb.push("<"); - for (var i = 0, k = this.typeParameters.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.typeParameters[i].serialize(sb); - } - sb.push(">"); - } - sb.push("("); - for (i = 0, k = this.parameters.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.parameters[i].serialize(sb); - } - if (this.returnType && !hasModifier(ModifierKind.SET, this.modifiers)) { - sb.push("): "); - (this.returnType).serialize(sb); - } else - sb.push(")"); - if (this.statements) { - sb.push(" {\n"); - for (i = 0, k = (this.statements).length; i < k; ++i) { - var statement: Statement = (this.statements)[i]; - statement.serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - sb.push("}"); - } - } } /** Represents an `if` statement. */ export class IfStatement extends Statement { - kind = NodeKind.IF; /** Condition. */ @@ -1712,45 +1246,19 @@ export class IfStatement extends Statement { ifTrue: Statement; /** Statement executed when condition is `false`. */ ifFalse: Statement | null; - - serialize(sb: string[]): void { - sb.push("if ("); - this.condition.serialize(sb); - sb.push(") "); - this.ifTrue.serialize(sb); - if (this.ifTrue.kind != NodeKind.BLOCK) - sb.push(";\n"); - if (this.ifFalse) { - if (this.ifTrue.kind == NodeKind.BLOCK) - sb.push(" else "); - else - sb.push("else "); - (this.ifFalse).serialize(sb); - } - } } /** Represents an `import` declaration, a single member within an {@link ImportStatement}. */ export class ImportDeclaration extends DeclarationStatement { - kind = NodeKind.IMPORTDECLARATION; modifiers = null; /** Identifier being imported. */ externalIdentifier: IdentifierExpression; - - serialize(sb: string[]): void { - this.externalIdentifier.serialize(sb); - if (this.externalIdentifier != this.name) { - sb.push(" as "); - (this.name).serialize(sb); - } - } } /** Represents an `import` statement. */ export class ImportStatement extends Statement { - kind = NodeKind.IMPORT; /** Array of member declarations or `null` if an asterisk import. */ @@ -1763,125 +1271,28 @@ export class ImportStatement extends Statement { normalizedPath: string; /** Mangled internal path being referenced. */ internalPath: string; - - serialize(sb: string[]): void { - sb.push("import "); - if (this.declarations) { - sb.push("{\n"); - for (var i: i32 = 0, k: i32 = this.declarations.length; i < k; ++i) { - if (i > 0) - sb.push(",\n"); - this.declarations[i].serialize(sb); - } - sb.push("\n} from "); - } else if (this.namespaceName) { - sb.push("* as "); - this.namespaceName.serialize(sb); - sb.push(" from "); - } - this.path.serialize(sb); - } } /** Represents an `interfarce` declaration. */ export class InterfaceDeclaration extends ClassDeclaration { - - kind = NodeKind.INTERFACE; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = this.modifiers.length; i < k; ++i) { - this.modifiers[i].serialize(sb); - sb.push(" "); - } - sb.push("interface "); - this.name.serialize(sb); - if (this.typeParameters.length) { - sb.push("<"); - for (i = 0, k = this.typeParameters.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.typeParameters[i].serialize(sb); - } - sb.push(">"); - } - if (this.extendsType) { - sb.push(" extends "); - this.extendsType.serialize(sb); - } - sb.push(" {\n"); - for (i = 0, k = this.members.length; i < k; ++i) { - this.members[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - sb.push("}"); - } + kind = NodeKind.INTERFACEDECLARATION; } /** Represents a method declaration within a `class`. */ export class MethodDeclaration extends FunctionDeclaration { - - kind = NodeKind.METHOD; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = this.modifiers.length; i < k; ++i) { - this.modifiers[i].serialize(sb); - sb.push(" "); - } - super.serializeCommon(sb); - } + kind = NodeKind.METHODDECLARATION; } /** Represents a `namespace` declaration. */ export class NamespaceDeclaration extends DeclarationStatement { - - kind = NodeKind.NAMESPACE; + kind = NodeKind.NAMESPACEDECLARATION; /** Array of namespace members. */ members: Statement[]; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = this.modifiers.length; i < k; ++i) { - this.modifiers[i].serialize(sb); - sb.push(" "); - } - sb.push("namespace "); - this.name.serialize(sb); - sb.push(" {\n"); - for (i = 0, k = this.members.length; i < k; ++i) { - this.members[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - sb.push("}"); - } } /** Represents a function parameter. */ export class Parameter extends Node { - kind = NodeKind.PARAMETER; /** Parameter name. */ @@ -1892,141 +1303,54 @@ export class Parameter extends Node { initializer: Expression | null; /** Whether a rest parameter or not. */ isRest: bool; - - serialize(sb: string[]): void { - if (this.isRest) - sb.push("..."); - this.name.serialize(sb); - if (this.type) { - sb.push(": "); - this.type.serialize(sb); - } - if (this.initializer) { - sb.push(" = "); - this.initializer.serialize(sb); - } - } } /** Represents a single modifier. */ export class Modifier extends Node { - kind = NodeKind.MODIFIER; /** Specific modifier kind. */ modifierKind: ModifierKind; - - serialize(sb: string[]): void { - sb.push(this.toString()); - } - - /** Returns the TypeScript representation of this modifier. */ - toString(): string { - switch (this.modifierKind) { - case ModifierKind.ABSTRACT: return "abstract"; - case ModifierKind.ASYNC: return "async"; - case ModifierKind.CONST: return "const"; - case ModifierKind.DECLARE: return "declare"; - case ModifierKind.EXPORT: return "export"; - case ModifierKind.GET: return "get"; - case ModifierKind.IMPORT: return "import"; - case ModifierKind.PRIVATE: return "private"; - case ModifierKind.PROTECTED: return "protected"; - case ModifierKind.PUBLIC: return "public"; - case ModifierKind.READONLY: return "readonly"; - case ModifierKind.SET: return "set"; - case ModifierKind.STATIC: return "static"; - default: assert(false); return ""; - } - } } /** Represents a `return` statement. */ export class ReturnStatement extends Statement { - kind = NodeKind.RETURN; /** Value expression being returned, if present. */ value: Expression | null; - - serialize(sb: string[]): void { - if (this.value) { - sb.push("return "); - this.value.serialize(sb); - } else - sb.push("return"); - } } /** Represents a single `case` within a `switch` statement. */ export class SwitchCase extends Node { - - kind = NodeKind.CASE; + kind = NodeKind.SWITCHCASE; /** Label expression. `null` indicates the default case. */ label: Expression | null; /** Contained statements. */ statements: Statement[]; - - serialize(sb: string[]): void { - if (this.label) { - sb.push("case "); - this.label.serialize(sb); - sb.push(":\n"); - } else - sb.push("default:\n"); - for (var i = 0, k = this.statements.length; i < k; ++i) { - if (i > 0) - sb.push("\n"); - this.statements[i].serialize(sb); - if (builderEndsWith(sb, CharCode.CLOSEBRACE)) - sb.push("\n"); - else - sb.push(";\n"); - } - } } /** Represents a `switch` statement. */ export class SwitchStatement extends Statement { - kind = NodeKind.SWITCH; /** Condition expression. */ condition: Expression; /** Contained cases. */ cases: SwitchCase[]; - - serialize(sb: string[]): void { - sb.push("switch ("); - this.condition.serialize(sb); - sb.push(") {\n"); - for (var i = 0, k = this.cases.length; i < k; ++i) { - this.cases[i].serialize(sb); - sb.push("\n"); - } - sb.push("}"); - } } /** Represents a `throw` statement. */ export class ThrowStatement extends Statement { - kind = NodeKind.THROW; /** Value expression being thrown. */ value: Expression; - - serialize(sb: string[]): void { - sb.push("throw "); - this.value.serialize(sb); - sb.push(";"); - } } /** Represents a `try` statement. */ export class TryStatement extends Statement { - kind = NodeKind.TRY; /** Contained statements. */ @@ -2037,84 +1361,26 @@ export class TryStatement extends Statement { catchStatements: Statement[] | null; /** Statements being executed in any case, if a `finally` clause is present. */ finallyStatements: Statement[] | null; - - serialize(sb: string[]): void { - sb.push("try {\n"); - for (var i = 0, k = this.statements.length; i < k; ++i) { - this.statements[i].serialize(sb); - sb.push(";\n"); - } - if (this.catchVariable) { - sb.push("} catch ("); - (this.catchVariable).serialize(sb); - sb.push(") {\n"); - if (this.catchStatements) - for (i = 0, k = (this.catchStatements).length; i < k; ++i) { - (this.catchStatements)[i].serialize(sb); - sb.push(";\n"); - } - } - if (this.finallyStatements) { - sb.push("} finally {\n"); - for (i = 0, k = (this.finallyStatements).length; i < k; ++i) { - (this.finallyStatements)[i].serialize(sb); - sb.push(";\n"); - } - } - sb.push("}"); - } } /** Represents a `type` declaration. */ export class TypeDeclaration extends DeclarationStatement { - kind = NodeKind.TYPEDECLARATION; /** Type being aliased. */ alias: TypeNode; - - serialize(sb: string[]): void { - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = (this.modifiers).length; i < k; ++i) { - (this.modifiers)[i].serialize(sb); - sb.push(" "); - } - sb.push("type "); - this.name.serialize(sb); - sb.push(" = "); - this.alias.serialize(sb); - } } /** Represents a single variable declaration within a {@link VariableStatement}. */ export class VariableDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.VARIABLEDECLARATION; /** Array of modifiers. */ modifiers: Modifier[] | null; - - serialize(sb: string[]): void { - this.name.serialize(sb); - if (this.type) { - sb.push(": "); - (this.type).serialize(sb); - } - if (this.initializer) { - sb.push(" = "); - (this.initializer).serialize(sb); - } - } } /** Represents a variable statement, i.e., a `var`, `let` or `const` statement. */ export class VariableStatement extends Statement { - kind = NodeKind.VARIABLE; /** Array of modifiers. */ @@ -2123,47 +1389,16 @@ export class VariableStatement extends Statement { decorators: Decorator[] | null; /** Array of member declarations. */ declarations: VariableDeclaration[]; - - serialize(sb: string[]): void { - var isConst = false; - if (this.decorators) - for (var i = 0, k = this.decorators.length; i < k; ++i) { - this.decorators[i].serialize(sb); - sb.push("\n"); - } - if (this.modifiers) - for (i = 0, k = this.modifiers.length; i < k; ++i) { - this.modifiers[i].serialize(sb); - sb.push(" "); - if (this.modifiers[i].modifierKind == ModifierKind.CONST) - isConst = true; - } - if (!isConst) - sb.push("let "); - for (i = 0, k = this.declarations.length; i < k; ++i) { - if (i > 0) - sb.push(", "); - this.declarations[i].serialize(sb); - } - } } /** Represents a `while` statement. */ export class WhileStatement extends Statement { - kind = NodeKind.WHILE; /** Condition expression. */ condition: Expression; /** Statement being looped over. */ statement: Statement; - - serialize(sb: string[]): void { - sb.push("while ("); - this.condition.serialize(sb); - sb.push(") "); - this.statement.serialize(sb); - } } /** Cached unused modifiers for reuse. */ @@ -2224,20 +1459,13 @@ export function hasDecorator(name: string, decorators: Decorator[] | null): bool return getFirstDecorator(name, decorators) != null; } -/** Serializes the specified node to its TypeScript representation. */ -export function serialize(node: Node): string { - var sb = new Array(); // shared builder could grow too much - node.serialize(sb); - return sb.join(""); -} - /** Mangles a path to an internal path. */ export function mangleInternalPath(path: string): string { - // TODO: not necessary with current config - /* if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH) - path = path.replace("/", PATH_DELIMITER); - if (PARENT_SUBST != "..") - path = path.replace("..", PARENT_SUBST); */ + // not necessary with current config + // if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH) + // path = path.replace("/", PATH_DELIMITER); + // if (PARENT_SUBST != "..") + // path = path.replace("..", PARENT_SUBST); return path; } @@ -2250,110 +1478,9 @@ export function mangleInternalName(declaration: DeclarationStatement): string { if (declaration.kind == NodeKind.VARIABLEDECLARATION && parent.kind == NodeKind.VARIABLE) // skip over if (!(parent = parent.parent)) return name; - if (parent.kind == NodeKind.CLASS) + if (parent.kind == NodeKind.CLASSDECLARATION) return (parent).internalName + (hasModifier(ModifierKind.STATIC, declaration.modifiers) ? STATIC_DELIMITER : INSTANCE_DELIMITER) + name; - if (parent.kind == NodeKind.NAMESPACE || parent.kind == NodeKind.ENUM) + if (parent.kind == NodeKind.NAMESPACEDECLARATION || parent.kind == NodeKind.ENUMDECLARATION) return (parent).internalName + STATIC_DELIMITER + name; return declaration.range.source.internalPath + PATH_DELIMITER + name; } - -/** Tests if the specified builder ends with the specified char code. */ -function builderEndsWith(sb: string[], code: CharCode): bool { - if (sb.length) { - var last = sb[sb.length - 1]; - return last.length > 0 ? last.charCodeAt(last.length - 1) == code : false; - } - return false; -} - -/** Converts a string to its literal representation including quotes. */ -export function stringToLiteral(str: string, singleQuoted: bool = false): string { - var ret = new Array(); - var off = 0; - for (var i = 0, k = str.length; i < k;) { - switch (str.charCodeAt(i)) { - - case CharCode.NULL: - if (i > off) - ret.push(str.substring(off, off = i + 1)); - ret.push("\\0"); - off = ++i; - break; - - case CharCode.BACKSPACE: - if (i > off) - ret.push(str.substring(off, i)); - off = ++i; - ret.push("\\b"); - break; - - case CharCode.TAB: - if (i > off) - ret.push(str.substring(off, i)); - off = ++i; - ret.push("\\t"); - break; - - case CharCode.LINEFEED: - if (i > off) - ret.push(str.substring(off, i)); - off = ++i; - ret.push("\\n"); - break; - - case CharCode.VERTICALTAB: - if (i > off) - ret.push(str.substring(off, i)); - off = ++i; - ret.push("\\v"); - break; - - case CharCode.FORMFEED: - if (i > off) - ret.push(str.substring(off, i)); - off = ++i; - ret.push("\\f"); - break; - - case CharCode.CARRIAGERETURN: - if (i > off) - ret.push(str.substring(off, i)); - ret.push("\\r"); - off = ++i; - break; - - case CharCode.DOUBLEQUOTE: - if (i > off) - ret.push(str.substring(off, i)); - ret.push("\\\""); - off = ++i; - break; - - case CharCode.SINGLEQUOTE: - if (i > off) - ret.push(str.substring(off, i)); - ret.push("\\'"); - off = ++i; - break; - - case CharCode.BACKSLASH: - if (i > off) - ret.push(str.substring(off, i)); - ret.push("\\\\"); - off = ++i; - break; - - default: - ++i; - break; - } - } - var quote = singleQuoted ? "'" : "\""; - if (off == 0) { - assert(ret.length == 0); - return quote + str + quote; - } - if (i > off) - ret.push(str.substring(off, i)); - return quote + ret.join("") + quote; -} diff --git a/src/compiler.ts b/src/compiler.ts index 5ea69994..0bab9821 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -275,17 +275,17 @@ export class Compiler extends DiagnosticEmitter { var statement = source.statements[i]; switch (statement.kind) { - case NodeKind.CLASS: + case NodeKind.CLASSDECLARATION: if ((noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (statement).modifiers)) && !(statement).typeParameters.length) this.compileClassDeclaration(statement, []); break; - case NodeKind.ENUM: + case NodeKind.ENUMDECLARATION: if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (statement).modifiers)) this.compileEnumDeclaration(statement); break; - case NodeKind.FUNCTION: + case NodeKind.FUNCTIONDECLARATION: if ((noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (statement).modifiers)) && !(statement).typeParameters.length) this.compileFunctionDeclaration(statement, []); break; @@ -294,7 +294,7 @@ export class Compiler extends DiagnosticEmitter { this.compileSourceByPath((statement).normalizedPath, (statement).path); break; - case NodeKind.NAMESPACE: + case NodeKind.NAMESPACEDECLARATION: if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (statement).modifiers)) this.compileNamespaceDeclaration(statement); break; @@ -608,27 +608,27 @@ export class Compiler extends DiagnosticEmitter { var member = members[i]; switch (member.kind) { - case NodeKind.CLASS: + case NodeKind.CLASSDECLARATION: if ((noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) && !(member).typeParameters.length) this.compileClassDeclaration(member, []); break; - case NodeKind.INTERFACE: + case NodeKind.INTERFACEDECLARATION: if ((noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) && !(member).typeParameters.length) this.compileInterfaceDeclaration(member, []); break; - case NodeKind.ENUM: + case NodeKind.ENUMDECLARATION: if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) this.compileEnumDeclaration(member); break; - case NodeKind.FUNCTION: + case NodeKind.FUNCTIONDECLARATION: if ((noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) && !(member).typeParameters.length) this.compileFunctionDeclaration(member, []); break; - case NodeKind.NAMESPACE: + case NodeKind.NAMESPACEDECLARATION: if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) this.compileNamespaceDeclaration(member); break; @@ -3059,12 +3059,12 @@ function isModuleExport(element: Element, declaration: DeclarationStatement): bo var parentNode = declaration.parent; if (!parentNode) return false; - if (declaration.range.source.isEntry && parentNode.kind != NodeKind.NAMESPACE) + if (declaration.range.source.isEntry && parentNode.kind != NodeKind.NAMESPACEDECLARATION) return true; if (parentNode.kind == NodeKind.VARIABLE) if (!(parentNode = parentNode.parent)) return false; - if (parentNode.kind != NodeKind.NAMESPACE && parentNode.kind != NodeKind.CLASS) + if (parentNode.kind != NodeKind.NAMESPACEDECLARATION && parentNode.kind != NodeKind.CLASSDECLARATION) return false; var parent = element.program.elements.get((parentNode).internalName); if (!parent) diff --git a/src/extra/README.md b/src/extra/README.md new file mode 100644 index 00000000..07fd0e9b --- /dev/null +++ b/src/extra/README.md @@ -0,0 +1 @@ +Extra components that are not ultimately required in a standalone compiler. diff --git a/src/extra/ast.ts b/src/extra/ast.ts new file mode 100644 index 00000000..4cf3c4fb --- /dev/null +++ b/src/extra/ast.ts @@ -0,0 +1,1213 @@ +import { + Token, + Range, + + Node, + NodeKind, + + Source, + + TypeNode, + TypeParameter, + + Expression, + IdentifierExpression, + LiteralExpression, + LiteralKind, + FloatLiteralExpression, + IntegerLiteralExpression, + StringLiteralExpression, + RegexpLiteralExpression, + ArrayLiteralExpression, + AssertionExpression, + AssertionKind, + BinaryExpression, + CallExpression, + CommaExpression, + ElementAccessExpression, + NewExpression, + ParenthesizedExpression, + PropertyAccessExpression, + TernaryExpression, + UnaryPostfixExpression, + UnaryExpression, + UnaryPrefixExpression, + + Statement, + BlockStatement, + BreakStatement, + ContinueStatement, + DoStatement, + EmptyStatement, + ExportImportStatement, + ExportStatement, + ExpressionStatement, + ForStatement, + IfStatement, + ImportStatement, + ReturnStatement, + SwitchStatement, + ThrowStatement, + TryStatement, + VariableStatement, + WhileStatement, + + DeclarationStatement, + ClassDeclaration, + EnumDeclaration, + EnumValueDeclaration, + FieldDeclaration, + FunctionDeclaration, + ImportDeclaration, + InterfaceDeclaration, + MethodDeclaration, + NamespaceDeclaration, + TypeDeclaration, + VariableDeclaration, + + Decorator, + Modifier, + ModifierKind, + Parameter, + ExportMember, + SwitchCase, + + hasModifier +} from "../ast"; + +import { + CharCode +} from "../util/charcode"; + +export function serializeNode(node: Node, sb: string[]): void { + switch (node.kind) { + + case NodeKind.SOURCE: + serializeSource(node, sb); + break; + + // types + + case NodeKind.TYPE: + serializeTypeNode(node, sb); + break; + + case NodeKind.TYPEPARAMETER: + serializeTypeParameter(node, sb); + break; + + // expressions + + case NodeKind.FALSE: + case NodeKind.NULL: + case NodeKind.SUPER: + case NodeKind.THIS: + case NodeKind.TRUE: + case NodeKind.CONSTRUCTOR: + case NodeKind.IDENTIFIER: + serializeIdentifierExpression(node, sb); + break; + + case NodeKind.ASSERTION: + serializeAssertionExpression(node, sb); + break; + + case NodeKind.BINARY: + serializeBinaryExpression(node, sb); + break; + + case NodeKind.CALL: + serializeCallExpression(node, sb); + break; + + case NodeKind.ELEMENTACCESS: + serializeElementAccessExpression(node, sb); + break; + + case NodeKind.LITERAL: + serializeLiteralExpression(node, sb); + break; + + case NodeKind.NEW: + serializeNewExpression(node, sb); + break; + + case NodeKind.PARENTHESIZED: + serializeParenthesizedExpression(node, sb); + break; + + case NodeKind.PROPERTYACCESS: + serializePropertyAccessExpression(node, sb); + break; + + case NodeKind.TERNARY: + serializeTernaryExpression(node, sb); + break; + + case NodeKind.UNARYPOSTFIX: + serializeUnaryPostfixExpression(node, sb); + break; + + case NodeKind.UNARYPREFIX: + serializeUnaryPrefixExpression(node, sb); + break; + + // statements + + case NodeKind.BLOCK: + serializeBlockStatement(node, sb); + break; + + case NodeKind.BREAK: + serializeBreakStatement(node, sb); + break; + + case NodeKind.CONTINUE: + serializeContinueStatement(node, sb); + break; + + case NodeKind.DO: + serializeDoStatement(node, sb); + break; + + case NodeKind.EMPTY: + serializeEmptyStatement(node, sb); + break; + + case NodeKind.EXPORT: + serializeExportStatement(node, sb); + break; + + case NodeKind.EXPORTIMPORT: + serializeExportImportStatement(node, sb); + break; + + case NodeKind.EXPRESSION: + serializeExpressionStatement(node, sb); + break; + + case NodeKind.FOR: + serializeForStatement(node, sb); + break; + + case NodeKind.IF: + serializeIfStatement(node, sb); + break; + + case NodeKind.IMPORT: + serializeImportStatement(node, sb); + break; + + case NodeKind.RETURN: + serializeReturnStatement(node, sb); + break; + + case NodeKind.SWITCH: + serializeSwitchStatement(node, sb); + break; + + case NodeKind.THROW: + serializeThrowStatement(node, sb); + break; + + case NodeKind.TRY: + serializeTryStatement(node, sb); + + case NodeKind.VARIABLE: + serializeVariableStatement(node, sb); + break; + + case NodeKind.WHILE: + serializeWhileStatement(node, sb); + break; + + // declaration statements + + case NodeKind.CLASSDECLARATION: + serializeClassDeclaration(node, sb); + break; + + case NodeKind.ENUMDECLARATION: + serializeEnumDeclaration(node, sb); + break; + + case NodeKind.ENUMVALUEDECLARATION: + serializeEnumValueDeclaration(node, sb); + break; + + case NodeKind.FIELDDECLARATION: + serializeFieldDeclaration(node, sb); + break; + + case NodeKind.FUNCTIONDECLARATION: + serializeFunctionDeclaration(node, sb); + break; + + case NodeKind.IMPORTDECLARATION: + serializeImportDeclaration(node, sb); + break; + + case NodeKind.INTERFACEDECLARATION: + serializeInterfaceDeclaration(node, sb); + break; + + case NodeKind.METHODDECLARATION: + serializeMethodDeclaration(node, sb); + break; + + case NodeKind.NAMESPACEDECLARATION: + serializeNamespaceDeclaration(node, sb); + break; + + case NodeKind.TYPEDECLARATION: + serializeTypeDeclaration(node, sb); + break; + + case NodeKind.VARIABLEDECLARATION: + serializeVariableDeclaration(node, sb); + break; + + // other + + case NodeKind.DECORATOR: + serializeDecorator(node, sb); + break; + + case NodeKind.EXPORTMEMBER: + serializeExportMember(node, sb); + break; + + case NodeKind.MODIFIER: + serializeModifier(node, sb); + break; + + case NodeKind.PARAMETER: + serializeParameter(node, sb); + break; + + case NodeKind.SWITCHCASE: + serializeSwitchCase(node, sb); + break; + + default: + assert(false); + break; + } +} + +export function serializeSource(source: Source, sb: string[]): void { + for (var i = 0, k = source.statements.length; i < k; ++i) { + serializeStatement(source.statements[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } +} + +// types + +export function serializeTypeNode(node: TypeNode, sb: string[]): void { + serializeIdentifierExpression(node.identifier, sb); + if (node.typeArguments.length) { + sb.push("<"); + for (var i = 0, k = node.typeArguments.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeNode(node.typeArguments[i], sb); + } + sb.push(">"); + } + if (node.isNullable) + sb.push(" | null"); +} + +export function serializeTypeParameter(node: TypeParameter, sb: string[]): void { + serializeIdentifierExpression(node.identifier, sb); + if (node.extendsType) { + sb.push(" extends "); + serializeTypeNode(node.extendsType, sb); + } +} + +// expressions + +export function serializeExpression(node: Expression, sb: string[]): void { + serializeNode(node, sb); +} + +export function serializeIdentifierExpression(node: IdentifierExpression, sb: string[]): void { + sb.push(node.name); +} + +export function serializeArrayLiteralExpression(node: ArrayLiteralExpression, sb: string[]): void { + sb.push("["); + for (var i = 0, k = node.elementExpressions.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + if (node.elementExpressions[i]) + serializeExpression(node.elementExpressions[i], sb); + } + sb.push("]"); +} + +export function serializeAssertionExpression(node: AssertionExpression, sb: string[]): void { + if (node.assertionKind == AssertionKind.PREFIX) { + sb.push("<"); + serializeTypeNode(node.toType, sb); + sb.push(">"); + serializeExpression(node.expression, sb); + } else { + serializeExpression(node.expression, sb); + sb.push(" as "); + serializeTypeNode(node.toType, sb); + } +} + +export function serializeBinaryExpression(node: BinaryExpression, sb: string[]): void { + serializeExpression(node.left, sb); + sb.push(" "); + sb.push(operatorToString(node.operator)); + sb.push(" "); + serializeExpression(node.right, sb); +} + +export function serializeCallExpression(node: CallExpression, sb: string[]): void { + serializeExpression(node.expression, sb); + var k: i32; + if (node.typeArguments && (k = node.typeArguments.length)) { + sb.push("<"); + for (var i = 0; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeNode(node.typeArguments[i], sb); + } + sb.push(">("); + } else + sb.push("("); + for (i = 0, k = node.arguments.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeExpression(node.arguments[i], sb); + } + sb.push(")"); +} + +export function serializeCommaExpression(node: CommaExpression, sb: string[]): void { + serializeExpression(node.expressions[0], sb); + for (var i = 1, k = node.expressions.length; i < k; ++i) { + sb.push(","); + serializeExpression(node.expressions[i], sb); + } +} + +export function serializeElementAccessExpression(node: ElementAccessExpression, sb: string[]): void { + serializeExpression(node.expression, sb); + sb.push("["); + serializeExpression(node.elementExpression, sb); + sb.push("]"); +} + +export function serializeLiteralExpression(node: LiteralExpression, sb: string[]): void { + switch (node.literalKind) { + + case LiteralKind.FLOAT: + serializeFloatLiteralExpression(node, sb); + break; + + case LiteralKind.INTEGER: + serializeIntegerLiteralExpression(node, sb); + break; + + case LiteralKind.STRING: + serializeStringLiteralExpression(node, sb); + break; + + case LiteralKind.REGEXP: + serializeRegexpLiteralExpression(node, sb); + break; + + case LiteralKind.ARRAY: + serializeArrayLiteralExpression(node, sb); + break; + + // case LiteralKind.OBJECT: + // serializeObjectLiteralExpression(node, sb); + // break; + + default: + assert(false); + break; + } +} + +export function serializeFloatLiteralExpression(node: FloatLiteralExpression, sb: string[]): void { + sb.push(node.value.toString(10)); +} + +export function serializeIntegerLiteralExpression(node: IntegerLiteralExpression, sb: string[]): void { + sb.push(node.value.toString()); +} + +export function serializeStringLiteral(str: string, sb: string[], singleQuoted: bool = false): void { + var off = 0; + sb.push(singleQuoted ? "'" : "\""); + for (var i = 0, k = str.length; i < k;) { + switch (str.charCodeAt(i)) { + + case CharCode.NULL: + if (i > off) + sb.push(str.substring(off, off = i + 1)); + sb.push("\\0"); + off = ++i; + break; + + case CharCode.BACKSPACE: + if (i > off) + sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\b"); + break; + + case CharCode.TAB: + if (i > off) + sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\t"); + break; + + case CharCode.LINEFEED: + if (i > off) + sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\n"); + break; + + case CharCode.VERTICALTAB: + if (i > off) + sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\v"); + break; + + case CharCode.FORMFEED: + if (i > off) + sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\f"); + break; + + case CharCode.CARRIAGERETURN: + if (i > off) + sb.push(str.substring(off, i)); + sb.push("\\r"); + off = ++i; + break; + + case CharCode.DOUBLEQUOTE: + if (!singleQuoted) { + if (i > off) + sb.push(str.substring(off, i)); + sb.push("\\\""); + off = ++i; + } else + ++i; + break; + + case CharCode.SINGLEQUOTE: + if (singleQuoted) { + if (i > off) + sb.push(str.substring(off, i)); + sb.push("\\'"); + off = ++i; + } else + ++i; + break; + + case CharCode.BACKSLASH: + if (i > off) + sb.push(str.substring(off, i)); + sb.push("\\\\"); + off = ++i; + break; + + default: + ++i; + break; + } + } + if (i > off) + sb.push(str.substring(off, i)); + sb.push(singleQuoted ? "'" : "\""); +} + +export function serializeStringLiteralExpression(node: StringLiteralExpression, sb: string[]): void { + serializeStringLiteral(node.value, sb); +} + +export function serializeRegexpLiteralExpression(node: RegexpLiteralExpression, sb: string[]): void { + sb.push("/"); + sb.push(node.pattern); + sb.push("/"); + sb.push(node.patternFlags); +} + +export function serializeNewExpression(node: NewExpression, sb: string[]): void { + sb.push("new "); + serializeCallExpression(node, sb); +} + +export function serializeParenthesizedExpression(node: ParenthesizedExpression, sb: string[]): void { + sb.push("("); + serializeExpression(node.expression, sb); + sb.push(")"); +} + +export function serializePropertyAccessExpression(node: PropertyAccessExpression, sb: string[]): void { + serializeExpression(node.expression, sb); + sb.push("."); + serializeIdentifierExpression(node.property, sb); +} + +export function serializeTernaryExpression(node: TernaryExpression, sb: string[]): void { + serializeExpression(node.condition, sb); + sb.push(" ? "); + serializeExpression(node.ifThen, sb); + sb.push(" : "); + serializeExpression(node.ifElse, sb); +} + +export function serializeUnaryExpression(node: UnaryExpression, sb: string[]): void { + switch (node.kind) { + + case NodeKind.UNARYPOSTFIX: + serializeUnaryPostfixExpression(node, sb); + break; + + case NodeKind.UNARYPREFIX: + serializeUnaryPrefixExpression(node, sb); + break; + + default: + assert(false); + break; + } +} + +export function operatorToString(token: Token): string { + switch (token) { + case Token.DELETE: return "delete"; + case Token.IN: return "in"; + case Token.INSTANCEOF: return "instanceof"; + case Token.NEW: return "new"; + case Token.TYPEOF: return "typeof"; + case Token.VOID: return "void"; + case Token.YIELD: return "yield"; + case Token.DOT_DOT_DOT: return "..."; + case Token.COMMA: return ","; + case Token.LESSTHAN: return "<"; + case Token.GREATERTHAN: return ">"; + case Token.LESSTHAN_EQUALS: return "<="; + case Token.GREATERTHAN_EQUALS: return ">="; + case Token.EQUALS_EQUALS: return "=="; + case Token.EXCLAMATION_EQUALS: return "!="; + case Token.EQUALS_EQUALS_EQUALS: return "==="; + case Token.EXCLAMATION_EQUALS_EQUALS: return "!=="; + case Token.PLUS: return "+"; + case Token.MINUS: return "-"; + case Token.ASTERISK_ASTERISK: return "**"; + case Token.ASTERISK: return "*"; + case Token.SLASH: return "/"; + case Token.PERCENT: return "%"; + case Token.PLUS_PLUS: return "++"; + case Token.MINUS_MINUS: return "--"; + case Token.LESSTHAN_LESSTHAN: return "<<"; + case Token.GREATERTHAN_GREATERTHAN: return ">>"; + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>"; + case Token.AMPERSAND: return "&"; + case Token.BAR: return "|"; + case Token.CARET: return "^"; + case Token.EXCLAMATION: return "!"; + case Token.TILDE: return "~"; + case Token.AMPERSAND_AMPERSAND: return "&&"; + case Token.BAR_BAR: return "||"; + case Token.EQUALS: return "="; + case Token.PLUS_EQUALS: return "+="; + case Token.MINUS_EQUALS: return "-="; + case Token.ASTERISK_EQUALS: return "*="; + case Token.ASTERISK_ASTERISK_EQUALS: return "**="; + case Token.SLASH_EQUALS: return "/="; + case Token.PERCENT_EQUALS: return "%="; + case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<="; + case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>="; + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>="; + case Token.AMPERSAND_EQUALS: return "&="; + case Token.BAR_EQUALS: return "|="; + case Token.CARET_EQUALS: return "^="; + default: assert(false); return ""; + } +} + +export function serializeUnaryPostfixExpression(node: UnaryPostfixExpression, sb: string[]): void { + serializeExpression(node.operand, sb); + sb.push(operatorToString(node.operator)); +} + +export function serializeUnaryPrefixExpression(node: UnaryPrefixExpression, sb: string[]): void { + sb.push(operatorToString(node.operator)); + serializeExpression(node.operand, sb); +} + +// statements + +export function serializeStatement(node: Statement, sb: string[]): void { + serializeNode(node, sb); +} + +export function serializeBlockStatement(node: BlockStatement, sb: string[]): void { + sb.push("{\n"); + for (var i = 0, k = node.statements.length; i < k; ++i) { + serializeStatement(node.statements[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } + sb.push("}"); +} + +export function serializeBreakStatement(node: BreakStatement, sb: string[]): void { + if (node.label) { + sb.push("break "); + serializeIdentifierExpression(node.label, sb); + } else + sb.push("break"); +} + +export function serializeContinueStatement(node: ContinueStatement, sb: string[]): void { + if (node.label) { + sb.push("continue "); + serializeIdentifierExpression(node.label, sb); + } else + sb.push("continue"); +} + +export function serializeClassDeclaration(node: ClassDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("class "); + sb.push(node.name.name); + if (node.typeParameters.length) { + sb.push("<"); + for (i = 0, k = node.typeParameters.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeParameter(node.typeParameters[i], sb); + } + sb.push(">"); + } + if (node.extendsType) { + sb.push(" extends "); + serializeTypeNode(node.extendsType, sb); + } + if (node.implementsTypes.length) { + sb.push(" implements "); + for (i = 0, k = node.implementsTypes.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeNode(node.implementsTypes[i], sb); + } + } + sb.push(" {\n"); + for (i = 0, k = node.members.length; i < k; ++i) { + serializeStatement(node.members[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } + sb.push("}"); +} + +export function serializeDoStatement(node: DoStatement, sb: string[]): void { + sb.push("do "); + serializeStatement(node.statement, sb); + if (node.statement.kind == NodeKind.BLOCK) + sb.push(" while ("); + else + sb.push(";\nwhile ("); + serializeExpression(node.condition, sb); + sb.push(")"); +} + +export function serializeEmptyStatement(node: EmptyStatement, sb: string[]): void { +} + +export function serializeEnumDeclaration(node: EnumDeclaration, sb: string[]): void { + if (node.modifiers) + for (var i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("enum "); + serializeIdentifierExpression(node.name, sb); + sb.push(" {\n"); + for (i = 0, k = node.values.length; i < k; ++i) { + if (i > 0) + sb.push(",\n"); + serializeEnumValueDeclaration(node.values[i], sb); + } + sb.push("\n}"); +} + +export function serializeEnumValueDeclaration(node: EnumValueDeclaration, sb: string[]): void { + serializeIdentifierExpression(node.name, sb); + if (node.value) { + sb.push(" = "); + serializeExpression(node.value, sb); + } +} + +export function serializeExportImportStatement(node: ExportImportStatement, sb: string[]): void { + sb.push("export import "); + serializeIdentifierExpression(node.externalIdentifier, sb); + sb.push(" = "); + serializeIdentifierExpression(node.identifier, sb); +} + +export function serializeExportMember(node: ExportMember, sb: string[]): void { + serializeIdentifierExpression(node.identifier, sb); + if (node.externalIdentifier.name != node.identifier.name) { + sb.push(" as "); + serializeIdentifierExpression(node.externalIdentifier, sb); + } +} + +export function serializeExportStatement(node: ExportStatement, sb: string[]): void { + if (node.modifiers) + for (var i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("export {\n"); + for (i = 0, k = node.members.length; i < k; ++i) { + if (i > 0) + sb.push(",\n"); + serializeExportMember(node.members[i], sb); + } + if (node.path) { + sb.push("\n} from "); + serializeStringLiteralExpression(node.path, sb); + } else + sb.push("\n}"); +} + +export function serializeExpressionStatement(node: ExpressionStatement, sb: string[]): void { + serializeExpression(node.expression, sb); +} + +export function serializeFieldDeclaration(node: FieldDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + serializeIdentifierExpression(node.name, sb); + if (node.type) { + sb.push(": "); + serializeTypeNode(node.type, sb); + } + if (node.initializer) { + sb.push(" = "); + serializeExpression(node.initializer, sb); + } +} + +export function serializeForStatement(node: ForStatement, sb: string[]): void { + sb.push("for ("); + if (node.initializer) + serializeStatement(node.initializer, sb); + if (node.condition) { + sb.push("; "); + serializeExpression(node.condition, sb); + } else + sb.push(";"); + if (node.incrementor) { + sb.push("; "); + serializeExpression(node.incrementor, sb); + } else + sb.push(";"); + sb.push(") "); + serializeStatement(node.statement, sb); +} + +export function serializeFunctionDeclaration(node: FunctionDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("function "); + serializeFunctionCommon(node, sb); +} + +function serializeFunctionCommon(node: FunctionDeclaration, sb: string[]): void { + serializeIdentifierExpression(node.name, sb); + if (node.typeParameters.length) { + sb.push("<"); + for (var i = 0, k = node.typeParameters.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeParameter(node.typeParameters[i], sb); + } + sb.push(">"); + } + sb.push("("); + for (i = 0, k = node.parameters.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeParameter(node.parameters[i], sb); + } + if (node.returnType && !hasModifier(ModifierKind.SET, node.modifiers)) { + sb.push("): "); + serializeTypeNode(node.returnType, sb); + } else + sb.push(")"); + if (node.statements) { + sb.push(" {\n"); + for (i = 0, k = node.statements.length; i < k; ++i) { + serializeStatement(node.statements[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } + sb.push("}"); + } +} + +export function serializeIfStatement(node: IfStatement, sb: string[]): void { + sb.push("if ("); + serializeExpression(node.condition, sb); + sb.push(") "); + serializeStatement(node.ifTrue, sb); + if (node.ifTrue.kind != NodeKind.BLOCK) + sb.push(";\n"); + if (node.ifFalse) { + if (node.ifTrue.kind == NodeKind.BLOCK) + sb.push(" else "); + else + sb.push("else "); + serializeStatement(node.ifFalse, sb); + } +} + +export function serializeImportDeclaration(node: ImportDeclaration, sb: string[]): void { + serializeIdentifierExpression(node.externalIdentifier, sb); + if (node.externalIdentifier != node.name) { + sb.push(" as "); + serializeIdentifierExpression(node.name, sb); + } +} + +export function serializeImportStatement(node: ImportStatement, sb: string[]): void { + sb.push("import "); + if (node.declarations) { + sb.push("{\n"); + for (var i: i32 = 0, k: i32 = node.declarations.length; i < k; ++i) { + if (i > 0) + sb.push(",\n"); + serializeImportDeclaration(node.declarations[i], sb); + } + sb.push("\n} from "); + } else if (node.namespaceName) { + sb.push("* as "); + serializeIdentifierExpression(node.namespaceName, sb); + sb.push(" from "); + } + serializeStringLiteralExpression(node.path, sb); +} + +export function serializeInterfaceDeclaration(node: InterfaceDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("interface "); + serializeIdentifierExpression(node.name, sb); + if (node.typeParameters.length) { + sb.push("<"); + for (i = 0, k = node.typeParameters.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeTypeParameter(node.typeParameters[i], sb); + } + sb.push(">"); + } + if (node.extendsType) { + sb.push(" extends "); + serializeTypeNode(node.extendsType, sb); + } + sb.push(" {\n"); + for (i = 0, k = node.members.length; i < k; ++i) { + serializeStatement(node.members[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } + sb.push("}"); +} + +export function serializeMethodDeclaration(node: MethodDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + serializeFunctionCommon(node, sb); +} + +export function serializeNamespaceDeclaration(node: NamespaceDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("namespace "); + serializeIdentifierExpression(node.name, sb); + sb.push(" {\n"); + for (i = 0, k = node.members.length; i < k; ++i) { + serializeStatement(node.members[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } + sb.push("}"); +} + +export function serializeReturnStatement(node: ReturnStatement, sb: string[]): void { + if (node.value) { + sb.push("return "); + serializeExpression(node.value, sb); + } else + sb.push("return"); +} + +export function serializeSwitchCase(node: SwitchCase, sb: string[]): void { + if (node.label) { + sb.push("case "); + serializeExpression(node.label, sb); + sb.push(":\n"); + } else + sb.push("default:\n"); + for (var i = 0, k = node.statements.length; i < k; ++i) { + if (i > 0) + sb.push("\n"); + serializeStatement(node.statements[i], sb); + if (builderEndsWith(sb, CharCode.CLOSEBRACE)) + sb.push("\n"); + else + sb.push(";\n"); + } +} + +export function serializeSwitchStatement(node: SwitchStatement, sb: string[]): void { + sb.push("switch ("); + serializeExpression(node.condition, sb); + sb.push(") {\n"); + for (var i = 0, k = node.cases.length; i < k; ++i) { + serializeSwitchCase(node.cases[i], sb); + sb.push("\n"); + } + sb.push("}"); +} + +export function serializeThrowStatement(node: ThrowStatement, sb: string[]): void { + sb.push("throw "); + serializeExpression(node.value, sb); + sb.push(";"); +} + +export function serializeTryStatement(node: TryStatement, sb: string[]): void { + sb.push("try {\n"); + for (var i = 0, k = node.statements.length; i < k; ++i) { + serializeStatement(node.statements[i], sb); + sb.push(";\n"); + } + if (node.catchVariable) { + sb.push("} catch ("); + serializeIdentifierExpression(node.catchVariable, sb); + sb.push(") {\n"); + if (node.catchStatements) + for (i = 0, k = node.catchStatements.length; i < k; ++i) { + serializeStatement(node.catchStatements[i], sb); + sb.push(";\n"); + } + } + if (node.finallyStatements) { + sb.push("} finally {\n"); + for (i = 0, k = node.finallyStatements.length; i < k; ++i) { + serializeStatement(node.finallyStatements[i], sb); + sb.push(";\n"); + } + } + sb.push("}"); +} + +export function serializeTypeDeclaration(node: TypeDeclaration, sb: string[]): void { + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + } + sb.push("type "); + serializeIdentifierExpression(node.name, sb); + sb.push(" = "); + serializeTypeNode(node.alias, sb); +} + +export function serializeVariableDeclaration(node: VariableDeclaration, sb: string[]): void { + serializeIdentifierExpression(node.name, sb); + if (node.type) { + sb.push(": "); + serializeTypeNode(node.type, sb); + } + if (node.initializer) { + sb.push(" = "); + serializeExpression(node.initializer, sb); + } +} + +export function serializeVariableStatement(node: VariableStatement, sb: string[]): void { + var isConst = false; + if (node.decorators) + for (var i = 0, k = node.decorators.length; i < k; ++i) { + serializeDecorator(node.decorators[i], sb); + sb.push("\n"); + } + if (node.modifiers) + for (i = 0, k = node.modifiers.length; i < k; ++i) { + serializeModifier(node.modifiers[i], sb); + sb.push(" "); + if (node.modifiers[i].modifierKind == ModifierKind.CONST) + isConst = true; + } + if (!isConst) + sb.push("var "); + for (i = 0, k = node.declarations.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeVariableDeclaration(node.declarations[i], sb); + } +} + +export function serializeWhileStatement(node: WhileStatement, sb: string[]): void { + sb.push("while ("); + serializeExpression(node.condition, sb); + sb.push(") "); + serializeStatement(node.statement, sb); +} + +// other + +export function serializeDecorator(node: Decorator, sb: string[]): void { + sb.push("@"); + serializeExpression(node.name, sb); + if (node.arguments) { + sb.push("("); + for (var i = 0, k = node.arguments.length; i < k; ++i) { + if (i > 0) + sb.push(", "); + serializeExpression(node.arguments[i], sb); + } + sb.push(")"); + } +} + +export function modifierToString(node: Modifier): string { + switch (node.modifierKind) { + case ModifierKind.ABSTRACT: return "abstract"; + case ModifierKind.ASYNC: return "async"; + case ModifierKind.CONST: return "const"; + case ModifierKind.DECLARE: return "declare"; + case ModifierKind.EXPORT: return "export"; + case ModifierKind.GET: return "get"; + case ModifierKind.IMPORT: return "import"; + case ModifierKind.PRIVATE: return "private"; + case ModifierKind.PROTECTED: return "protected"; + case ModifierKind.PUBLIC: return "public"; + case ModifierKind.READONLY: return "readonly"; + case ModifierKind.SET: return "set"; + case ModifierKind.STATIC: return "static"; + default: assert(false); return ""; + } +} + +export function serializeModifier(node: Modifier, sb: string[]): void { + sb.push(modifierToString(node)); +} + +export function serializeParameter(node: Parameter, sb: string[]): void { + if (node.isRest) + sb.push("..."); + serializeIdentifierExpression(node.name, sb); + if (node.type) { + sb.push(": "); + serializeTypeNode(node.type, sb); + } + if (node.initializer) { + sb.push(" = "); + serializeExpression(node.initializer, sb); + } +} + +// helpers + +function builderEndsWith(sb: string[], code: CharCode): bool { + if (sb.length) { + var last = sb[sb.length - 1]; + return last.length > 0 ? last.charCodeAt(last.length - 1) == code : false; + } + return false; +} diff --git a/src/glue/README.md b/src/glue/README.md new file mode 100644 index 00000000..d0068925 --- /dev/null +++ b/src/glue/README.md @@ -0,0 +1 @@ +Environment specific glue code. diff --git a/src/program.ts b/src/program.ts index 9dcdd978..55d3010a 100644 --- a/src/program.ts +++ b/src/program.ts @@ -156,11 +156,11 @@ export class Program extends DiagnosticEmitter { var statement = statements[j]; switch (statement.kind) { - case NodeKind.CLASS: + case NodeKind.CLASSDECLARATION: this.initializeClass(statement, queuedDerivedClasses); break; - case NodeKind.ENUM: + case NodeKind.ENUMDECLARATION: this.initializeEnum(statement); break; @@ -168,7 +168,7 @@ export class Program extends DiagnosticEmitter { this.initializeExports(statement, queuedExports); break; - case NodeKind.FUNCTION: + case NodeKind.FUNCTIONDECLARATION: this.initializeFunction(statement); break; @@ -176,11 +176,11 @@ export class Program extends DiagnosticEmitter { this.initializeImports(statement, queuedExports, queuedImports); break; - case NodeKind.INTERFACE: + case NodeKind.INTERFACEDECLARATION: this.initializeInterface(statement); break; - case NodeKind.NAMESPACE: + case NodeKind.NAMESPACEDECLARATION: this.initializeNamespace(statement, queuedDerivedClasses, null); break; @@ -327,11 +327,11 @@ export class Program extends DiagnosticEmitter { var memberDeclaration = memberDeclarations[i]; switch (memberDeclaration.kind) { - case NodeKind.FIELD: + case NodeKind.FIELDDECLARATION: this.initializeField(memberDeclaration, prototype); break; - case NodeKind.METHOD: + case NodeKind.METHODDECLARATION: var isGetter: bool; if ((isGetter = hasModifier(ModifierKind.GET, memberDeclaration.modifiers)) || hasModifier(ModifierKind.SET, memberDeclaration.modifiers)) this.initializeAccessor(memberDeclaration, prototype, isGetter); @@ -768,11 +768,11 @@ export class Program extends DiagnosticEmitter { var memberDeclaration = memberDeclarations[i]; switch (memberDeclaration.kind) { - case NodeKind.FIELD: + case NodeKind.FIELDDECLARATION: this.initializeField(memberDeclaration, prototype); break; - case NodeKind.METHOD: + case NodeKind.METHODDECLARATION: var isGetter: bool; if ((isGetter = hasModifier(ModifierKind.GET, memberDeclaration.modifiers)) || hasModifier(ModifierKind.SET, memberDeclaration.modifiers)) this.initializeAccessor(memberDeclaration, prototype, isGetter); @@ -818,23 +818,23 @@ export class Program extends DiagnosticEmitter { for (var i = 0, k = members.length; i < k; ++i) { switch (members[i].kind) { - case NodeKind.CLASS: + case NodeKind.CLASSDECLARATION: this.initializeClass(members[i], queuedExtendingClasses, namespace); break; - case NodeKind.ENUM: + case NodeKind.ENUMDECLARATION: this.initializeEnum(members[i], namespace); break; - case NodeKind.FUNCTION: + case NodeKind.FUNCTIONDECLARATION: this.initializeFunction(members[i], namespace); break; - case NodeKind.INTERFACE: + case NodeKind.INTERFACEDECLARATION: this.initializeInterface(members[i], namespace); break; - case NodeKind.NAMESPACE: + case NodeKind.NAMESPACEDECLARATION: this.initializeNamespace(members[i], queuedExtendingClasses, namespace); break; diff --git a/src/tokenizer.ts b/src/tokenizer.ts index dae74f32..8cc6c8d3 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -249,60 +249,6 @@ export namespace Token { } } - export function operatorToString(token: Token): string { - switch (token) { - case Token.DELETE: return "delete"; - case Token.IN: return "in"; - case Token.INSTANCEOF: return "instanceof"; - case Token.NEW: return "new"; - case Token.TYPEOF: return "typeof"; - case Token.VOID: return "void"; - case Token.YIELD: return "yield"; - case Token.DOT_DOT_DOT: return "..."; - case Token.COMMA: return ","; - case Token.LESSTHAN: return "<"; - case Token.GREATERTHAN: return ">"; - case Token.LESSTHAN_EQUALS: return "<="; - case Token.GREATERTHAN_EQUALS: return ">="; - case Token.EQUALS_EQUALS: return "=="; - case Token.EXCLAMATION_EQUALS: return "!="; - case Token.EQUALS_EQUALS_EQUALS: return "==="; - case Token.EXCLAMATION_EQUALS_EQUALS: return "!=="; - case Token.PLUS: return "+"; - case Token.MINUS: return "-"; - case Token.ASTERISK_ASTERISK: return "**"; - case Token.ASTERISK: return "*"; - case Token.SLASH: return "/"; - case Token.PERCENT: return "%"; - case Token.PLUS_PLUS: return "++"; - case Token.MINUS_MINUS: return "--"; - case Token.LESSTHAN_LESSTHAN: return "<<"; - case Token.GREATERTHAN_GREATERTHAN: return ">>"; - case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>"; - case Token.AMPERSAND: return "&"; - case Token.BAR: return "|"; - case Token.CARET: return "^"; - case Token.EXCLAMATION: return "!"; - case Token.TILDE: return "~"; - case Token.AMPERSAND_AMPERSAND: return "&&"; - case Token.BAR_BAR: return "||"; - case Token.EQUALS: return "="; - case Token.PLUS_EQUALS: return "+="; - case Token.MINUS_EQUALS: return "-="; - case Token.ASTERISK_EQUALS: return "*="; - case Token.ASTERISK_ASTERISK_EQUALS: return "**="; - case Token.SLASH_EQUALS: return "/="; - case Token.PERCENT_EQUALS: return "%="; - case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<="; - case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>="; - case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>="; - case Token.AMPERSAND_EQUALS: return "&="; - case Token.BAR_EQUALS: return "|="; - case Token.CARET_EQUALS: return "^="; - default: assert(false); return ""; - } - } - export function isAlsoIdentifier(token: Token): bool { switch (token) { case Token.ABSTRACT: diff --git a/src/tsconfig.json b/src/tsconfig.json index f44161e6..bc4def2b 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,5 +6,8 @@ }, "include": [ "./**/*.ts" + ], + "exclude": [ + "./extra/**" ] } diff --git a/std/README.md b/std/README.md new file mode 100644 index 00000000..29321c51 --- /dev/null +++ b/std/README.md @@ -0,0 +1,3 @@ +Standard library components for use with `tsc` (portable) and `asc` (assembly). + +Definition files (.d.ts) and base configurations (.json) are relevant to `tsc` only and not used by `asc`. diff --git a/std/tsconfig.json b/std/tsconfig.json deleted file mode 100644 index 2daed60f..00000000 --- a/std/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../tsconfig-base.json" -} diff --git a/tests/parser.js b/tests/parser.js index 330017fe..a7a191de 100644 --- a/tests/parser.js +++ b/tests/parser.js @@ -7,6 +7,7 @@ require("ts-node").register({ project: require("path").join(__dirname, "..", "sr require("../src/glue/js"); var Parser = require("../src/parser").Parser; +var serializeSource = require("../src/extra/ast").serializeSource; var isCreate = process.argv[2] === "--create"; var filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "**.ts"; @@ -25,7 +26,7 @@ glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => { parser.parseFile(sourceText, filename, true); var sb = []; - parser.program.sources[0].serialize(sb); + serializeSource(parser.program.sources[0], sb); var actual = sb.join("") + parser.diagnostics.map(diagnostic => "// " + diagnostic + "\n").join("");; var fixture = filename + ".fixture.ts"; diff --git a/tests/parser/for.ts b/tests/parser/for.ts index 79906e75..3e10da95 100644 --- a/tests/parser/for.ts +++ b/tests/parser/for.ts @@ -1,4 +1,4 @@ -for (let i: i32 = 0; i < 10; ++i) { +for (var i: i32 = 0; i < 10; ++i) { ; } for (i = 0; i < 10; ++i) { diff --git a/tests/parser/for.ts.fixture.ts b/tests/parser/for.ts.fixture.ts index 5f436e9a..02ca618e 100644 --- a/tests/parser/for.ts.fixture.ts +++ b/tests/parser/for.ts.fixture.ts @@ -1,4 +1,4 @@ -for (let i: i32 = 0; i < 10; ++i) { +for (var i: i32 = 0; i < 10; ++i) { ; } for (i = 0; i < 10; ++i) { diff --git a/tests/parser/namespace.ts b/tests/parser/namespace.ts index f5242b01..ea8b6379 100644 --- a/tests/parser/namespace.ts +++ b/tests/parser/namespace.ts @@ -1,7 +1,7 @@ declare namespace A { namespace B { export namespace C { - let aVar: i32; + var aVar: i32; const aConst: i32 = 0; function aFunc(): void {} enum AnEnum {} diff --git a/tests/parser/namespace.ts.fixture.ts b/tests/parser/namespace.ts.fixture.ts index 2855800a..e9a1ebde 100644 --- a/tests/parser/namespace.ts.fixture.ts +++ b/tests/parser/namespace.ts.fixture.ts @@ -1,7 +1,7 @@ declare namespace A { namespace B { export namespace C { -let aVar: i32; +var aVar: i32; const aConst: i32 = 0; function aFunc(): void { } diff --git a/tests/parser/regexp.ts.fixture.ts b/tests/parser/regexp.ts.fixture.ts index b60acade..fd046c41 100644 --- a/tests/parser/regexp.ts.fixture.ts +++ b/tests/parser/regexp.ts.fixture.ts @@ -1,7 +1,7 @@ /(abc)\//ig; /(abc)\//; -let re = /(abc)\//ig; -let noRe = !/(abc)\//i; +var re = /(abc)\//ig; +var noRe = !/(abc)\//i; b / ig; /(abc)\//iig; /(abc)\//iX; diff --git a/tests/parser/var.ts b/tests/parser/var.ts index 5cfb2d6a..fe68a424 100644 --- a/tests/parser/var.ts +++ b/tests/parser/var.ts @@ -1,7 +1,7 @@ var a: i32; -let b: i32; +var b: i32; const c: i32 = 0; -let d = 2; +var d = 2; -let e; // type expected +var e; // type expected const f: i32; // must be initialized diff --git a/tests/parser/var.ts.fixture.ts b/tests/parser/var.ts.fixture.ts index 095fa3e2..fe6b7c4d 100644 --- a/tests/parser/var.ts.fixture.ts +++ b/tests/parser/var.ts.fixture.ts @@ -1,8 +1,8 @@ -let a: i32; -let b: i32; +var a: i32; +var b: i32; const c: i32 = 0; -let d = 2; -let e; +var d = 2; +var e; const f: i32; // ERROR 1110: "Type expected." in var.ts @ 59,59 // ERROR 1155: "'const' declarations must be initialized." in var.ts @ 84,85