Initial support for default imports/exports, see #98

Does not implement combinations like 'import theDefault, *' yet
This commit is contained in:
dcode 2019-06-04 08:55:22 +02:00
parent 27e54ed07b
commit fa667386d9
20 changed files with 336 additions and 73 deletions

View File

@ -39,9 +39,6 @@
"no-debugger": { "no-debugger": {
"severity": "error" "severity": "error"
}, },
"no-default-export": {
"severity": "error"
},
"no-duplicate-super": { "no-duplicate-super": {
"severity": "error" "severity": "error"
}, },

View File

@ -67,6 +67,7 @@ export enum NodeKind {
DO, DO,
EMPTY, EMPTY,
EXPORT, EXPORT,
EXPORTDEFAULT,
EXPORTIMPORT, EXPORTIMPORT,
EXPRESSION, EXPRESSION,
FOR, FOR,
@ -701,6 +702,16 @@ export abstract class Node {
return stmt; return stmt;
} }
static createExportDefaultStatement(
declaration: DeclarationStatement,
range: Range
): ExportDefaultStatement {
var stmt = new ExportDefaultStatement();
stmt.declaration = declaration;
stmt.range = range;
return stmt;
}
static createExportImportStatement( static createExportImportStatement(
name: IdentifierExpression, name: IdentifierExpression,
externalName: IdentifierExpression, externalName: IdentifierExpression,
@ -1775,6 +1786,14 @@ export class ExportStatement extends Statement {
isDeclare: bool; isDeclare: bool;
} }
/** Represents an `export default` statement. */
export class ExportDefaultStatement extends Statement {
kind = NodeKind.EXPORTDEFAULT;
/** Declaration being exported as default. */
declaration: DeclarationStatement;
}
/** Represents an expression that is used as a statement. */ /** Represents an expression that is used as a statement. */
export class ExpressionStatement extends Statement { export class ExpressionStatement extends Statement {
kind = NodeKind.EXPRESSION; kind = NodeKind.EXPRESSION;

View File

@ -156,7 +156,8 @@ import {
nodeIsConstantValue, nodeIsConstantValue,
findDecorator, findDecorator,
isTypeOmitted isTypeOmitted,
ExportDefaultStatement
} from "./ast"; } from "./ast";
import { import {
@ -1619,6 +1620,9 @@ export class Compiler extends DiagnosticEmitter {
// === Statements =============================================================================== // === Statements ===============================================================================
compileTopLevelStatement(statement: Statement, body: ExpressionRef[]): void { compileTopLevelStatement(statement: Statement, body: ExpressionRef[]): void {
if (statement.kind == NodeKind.EXPORTDEFAULT) {
statement = (<ExportDefaultStatement>statement).declaration;
}
switch (statement.kind) { switch (statement.kind) {
case NodeKind.CLASSDECLARATION: { case NodeKind.CLASSDECLARATION: {
let memberStatements = (<ClassDeclaration>statement).members; let memberStatements = (<ClassDeclaration>statement).members;

View File

@ -66,6 +66,7 @@ export enum DiagnosticCode {
Type_expected = 1110, Type_expected = 1110,
A_default_clause_cannot_appear_more_than_once_in_a_switch_statement = 1113, A_default_clause_cannot_appear_more_than_once_in_a_switch_statement = 1113,
Duplicate_label_0 = 1114, Duplicate_label_0 = 1114,
An_export_assignment_cannot_have_modifiers = 1120,
Octal_literals_are_not_allowed_in_strict_mode = 1121, Octal_literals_are_not_allowed_in_strict_mode = 1121,
Digit_expected = 1124, Digit_expected = 1124,
Hexadecimal_digit_expected = 1125, Hexadecimal_digit_expected = 1125,
@ -204,6 +205,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1110: return "Type expected."; case 1110: return "Type expected.";
case 1113: return "A 'default' clause cannot appear more than once in a 'switch' statement."; case 1113: return "A 'default' clause cannot appear more than once in a 'switch' statement.";
case 1114: return "Duplicate label '{0}'."; case 1114: return "Duplicate label '{0}'.";
case 1120: return "An export assignment cannot have modifiers.";
case 1121: return "Octal literals are not allowed in strict mode."; case 1121: return "Octal literals are not allowed in strict mode.";
case 1124: return "Digit expected."; case 1124: return "Digit expected.";
case 1125: return "Hexadecimal digit expected."; case 1125: return "Hexadecimal digit expected.";

View File

@ -59,6 +59,7 @@
"Type expected.": 1110, "Type expected.": 1110,
"A 'default' clause cannot appear more than once in a 'switch' statement.": 1113, "A 'default' clause cannot appear more than once in a 'switch' statement.": 1113,
"Duplicate label '{0}'.": 1114, "Duplicate label '{0}'.": 1114,
"An export assignment cannot have modifiers.": 1120,
"Octal literals are not allowed in strict mode.": 1121, "Octal literals are not allowed in strict mode.": 1121,
"Digit expected.": 1124, "Digit expected.": 1124,
"Hexadecimal digit expected.": 1125, "Hexadecimal digit expected.": 1125,

View File

@ -52,6 +52,7 @@ import {
EmptyStatement, EmptyStatement,
ExportImportStatement, ExportImportStatement,
ExportStatement, ExportStatement,
ExportDefaultStatement,
ExpressionStatement, ExpressionStatement,
ForStatement, ForStatement,
IfStatement, IfStatement,
@ -230,6 +231,10 @@ export class ASTBuilder {
this.visitExportStatement(<ExportStatement>node); this.visitExportStatement(<ExportStatement>node);
break; break;
} }
case NodeKind.EXPORTDEFAULT: {
this.visitExportDefaultStatement(<ExportDefaultStatement>node);
break;
}
case NodeKind.EXPORTIMPORT: { case NodeKind.EXPORTIMPORT: {
this.visitExportImportStatement(<ExportImportStatement>node); this.visitExportImportStatement(<ExportImportStatement>node);
break; break;
@ -851,15 +856,19 @@ export class ASTBuilder {
} }
} }
visitClassDeclaration(node: ClassDeclaration): void { visitClassDeclaration(node: ClassDeclaration, isDefault: bool = false): void {
var decorators = node.decorators; var decorators = node.decorators;
if (decorators) { if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) { for (let i = 0, k = decorators.length; i < k; ++i) {
this.serializeDecorator(decorators[i]); this.serializeDecorator(decorators[i]);
} }
} }
this.serializeExternalModifiers(node);
var sb = this.sb; var sb = this.sb;
if (isDefault) {
sb.push("export default ");
} else {
this.serializeExternalModifiers(node);
}
if (node.is(CommonFlags.ABSTRACT)) sb.push("abstract "); if (node.is(CommonFlags.ABSTRACT)) sb.push("abstract ");
if (node.name.text.length) { if (node.name.text.length) {
sb.push("class "); sb.push("class ");
@ -931,9 +940,13 @@ export class ASTBuilder {
visitEmptyStatement(node: EmptyStatement): void { visitEmptyStatement(node: EmptyStatement): void {
} }
visitEnumDeclaration(node: EnumDeclaration): void { visitEnumDeclaration(node: EnumDeclaration, isDefault: bool = false): void {
var sb = this.sb; var sb = this.sb;
this.serializeExternalModifiers(node); if (isDefault) {
sb.push("export default ");
} else {
this.serializeExternalModifiers(node);
}
if (node.is(CommonFlags.CONST)) sb.push("const "); if (node.is(CommonFlags.CONST)) sb.push("const ");
sb.push("enum "); sb.push("enum ");
this.visitIdentifierExpression(node.name); this.visitIdentifierExpression(node.name);
@ -1011,6 +1024,33 @@ export class ASTBuilder {
sb.push(";"); 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 { visitExpressionStatement(node: ExpressionStatement): void {
this.visitNode(node.expression); this.visitNode(node.expression);
} }
@ -1065,7 +1105,7 @@ export class ASTBuilder {
this.visitNode(node.statement); this.visitNode(node.statement);
} }
visitFunctionDeclaration(node: FunctionDeclaration): void { visitFunctionDeclaration(node: FunctionDeclaration, isDefault: bool = false): void {
var sb = this.sb; var sb = this.sb;
var decorators = node.decorators; var decorators = node.decorators;
if (decorators) { if (decorators) {
@ -1073,8 +1113,12 @@ export class ASTBuilder {
this.serializeDecorator(decorators[i]); this.serializeDecorator(decorators[i]);
} }
} }
this.serializeExternalModifiers(node); if (isDefault) {
this.serializeAccessModifiers(node); sb.push("export default ");
} else {
this.serializeExternalModifiers(node);
this.serializeAccessModifiers(node);
}
if (node.name.text.length) { if (node.name.text.length) {
sb.push("function "); sb.push("function ");
} else { } else {
@ -1230,15 +1274,19 @@ export class ASTBuilder {
this.visitTypeNode(node.valueType); this.visitTypeNode(node.valueType);
} }
visitInterfaceDeclaration(node: InterfaceDeclaration): void { visitInterfaceDeclaration(node: InterfaceDeclaration, isDefault: bool = false): void {
var decorators = node.decorators; var decorators = node.decorators;
if (decorators) { if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) { for (let i = 0, k = decorators.length; i < k; ++i) {
this.serializeDecorator(decorators[i]); this.serializeDecorator(decorators[i]);
} }
} }
this.serializeExternalModifiers(node);
var sb = this.sb; var sb = this.sb;
if (isDefault) {
sb.push("export default ");
} else {
this.serializeExternalModifiers(node);
}
sb.push("interface "); sb.push("interface ");
this.visitIdentifierExpression(node.name); this.visitIdentifierExpression(node.name);
var typeParameters = node.typeParameters; var typeParameters = node.typeParameters;
@ -1284,15 +1332,19 @@ export class ASTBuilder {
this.visitFunctionCommon(node); this.visitFunctionCommon(node);
} }
visitNamespaceDeclaration(node: NamespaceDeclaration): void { visitNamespaceDeclaration(node: NamespaceDeclaration, isDefault: bool = false): void {
var decorators = node.decorators; var decorators = node.decorators;
if (decorators) { if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) { for (let i = 0, k = decorators.length; i < k; ++i) {
this.serializeDecorator(decorators[i]); this.serializeDecorator(decorators[i]);
} }
} }
this.serializeExternalModifiers(node);
var sb = this.sb; var sb = this.sb;
if (isDefault) {
sb.push("export default ");
} else {
this.serializeExternalModifiers(node);
}
sb.push("namespace "); sb.push("namespace ");
this.visitIdentifierExpression(node.name); this.visitIdentifierExpression(node.name);
var members = node.members; var members = node.members;

View File

@ -171,31 +171,34 @@ export class Parser extends DiagnosticEmitter {
// check modifiers // check modifiers
var exportStart: i32 = 0; var exportStart: i32 = 0;
var exportEnd: i32 = 0; var exportEnd: i32 = 0;
var defaultStart: i32 = 0;
var defaultEnd: i32 = 0;
if (tn.skip(Token.EXPORT)) { if (tn.skip(Token.EXPORT)) {
if (tn.skip(Token.DEFAULT)) {
this.error(
DiagnosticCode.Operation_not_supported,
tn.range()
);
}
if (startPos < 0) startPos = tn.tokenPos; if (startPos < 0) startPos = tn.tokenPos;
flags |= CommonFlags.EXPORT; flags |= CommonFlags.EXPORT;
exportStart = tn.tokenPos; exportStart = tn.tokenPos;
exportEnd = tn.pos; exportEnd = tn.pos;
if (tn.skip(Token.DEFAULT)) {
defaultStart = tn.tokenPos;
defaultEnd = tn.pos;
}
} }
var declareStart: i32 = 0; var declareStart: i32 = 0;
var declareEnd: i32 = 0; var declareEnd: i32 = 0;
var contextIsAmbient = namespace != null && namespace.is(CommonFlags.AMBIENT); var contextIsAmbient = namespace != null && namespace.is(CommonFlags.AMBIENT);
if (tn.skip(Token.DECLARE)) { if (tn.skip(Token.DECLARE)) {
if (startPos < 0) startPos = tn.tokenPos;
if (contextIsAmbient) { if (contextIsAmbient) {
this.error( this.error(
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
tn.range() tn.range()
); // recoverable ); // recoverable
} else {
if (startPos < 0) startPos = tn.tokenPos;
declareStart = startPos;
declareEnd = tn.pos;
flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT;
} }
flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT;
} else if (contextIsAmbient) { } else if (contextIsAmbient) {
flags |= CommonFlags.AMBIENT; flags |= CommonFlags.AMBIENT;
} }
@ -297,7 +300,18 @@ export class Parser extends DiagnosticEmitter {
// handle plain exports // handle plain exports
if (flags & CommonFlags.EXPORT) { if (flags & CommonFlags.EXPORT) {
statement = this.parseExport(tn, startPos, (flags & CommonFlags.DECLARE) != 0); if (defaultEnd && tn.skipIdentifier(IdentifierHandling.PREFER)) {
if (declareEnd) {
this.error(
DiagnosticCode.An_export_assignment_cannot_have_modifiers,
tn.range(declareStart, declareEnd)
);
}
statement = this.parseExportDefaultAlias(tn, startPos, defaultStart, defaultEnd);
defaultStart = defaultEnd = 0; // consume
} else {
statement = this.parseExport(tn, startPos, (flags & CommonFlags.DECLARE) != 0);
}
// handle non-declaration statements // handle non-declaration statements
} else { } else {
@ -330,6 +344,25 @@ export class Parser extends DiagnosticEmitter {
); );
} }
} }
// check if this an `export default` declaration
if (defaultEnd && statement !== null) {
switch (statement.kind) {
case NodeKind.ENUMDECLARATION:
case NodeKind.FUNCTIONDECLARATION:
case NodeKind.CLASSDECLARATION:
case NodeKind.INTERFACEDECLARATION:
case NodeKind.NAMESPACEDECLARATION: {
return Node.createExportDefaultStatement(<DeclarationStatement>statement, tn.range(startPos, tn.pos));
}
default: {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(defaultStart, defaultEnd), "default"
);
}
}
}
return statement; return statement;
} }
@ -2318,6 +2351,28 @@ export class Parser extends DiagnosticEmitter {
return null; return null;
} }
parseExportDefaultAlias(
tn: Tokenizer,
startPos: i32,
defaultStart: i32,
defaultEnd: i32
): ExportStatement {
// at 'export' 'default': [Known-To-Be-]Identifier
var name = tn.readIdentifier();
var range = tn.range();
var ret = Node.createExportStatement([
Node.createExportMember(
Node.createIdentifierExpression(name, range),
Node.createIdentifierExpression("default", tn.range(defaultStart, defaultEnd)),
range
)
], null, false, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON);
return ret;
}
parseImport( parseImport(
tn: Tokenizer tn: Tokenizer
): ImportStatement | null { ): ImportStatement | null {
@ -2330,7 +2385,7 @@ export class Parser extends DiagnosticEmitter {
var members: ImportDeclaration[] | null = null; var members: ImportDeclaration[] | null = null;
var namespaceName: IdentifierExpression | null = null; var namespaceName: IdentifierExpression | null = null;
var skipFrom = false; var skipFrom = false;
if (tn.skip(Token.OPENBRACE)) { if (tn.skip(Token.OPENBRACE)) { // import { ... } from "file"
members = new Array(); members = new Array();
while (!tn.skip(Token.CLOSEBRACE)) { while (!tn.skip(Token.CLOSEBRACE)) {
let member = this.parseImportDeclaration(tn); let member = this.parseImportDeclaration(tn);
@ -2348,7 +2403,7 @@ export class Parser extends DiagnosticEmitter {
} }
} }
} }
} else if (tn.skip(Token.ASTERISK)) { } else if (tn.skip(Token.ASTERISK)) { // import * from "file"
if (tn.skip(Token.AS)) { if (tn.skip(Token.AS)) {
if (tn.skipIdentifier()) { if (tn.skipIdentifier()) {
namespaceName = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); namespaceName = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
@ -2366,7 +2421,25 @@ export class Parser extends DiagnosticEmitter {
); );
return null; return null;
} }
} else { } else if (tn.skip(Token.IDENTIFIER, IdentifierHandling.PREFER)) { // import Name from "file"
let name = tn.readIdentifier();
let range = tn.range();
members = [
Node.createImportDeclaration(
Node.createIdentifierExpression("default", range),
Node.createIdentifierExpression(name, range),
range
)
];
if (tn.skip(Token.COMMA)) {
// TODO: default + star, default + members
this.error(
DiagnosticCode.Operation_not_supported,
tn.range()
);
return null;
}
} else { // import "file"
skipFrom = true; skipFrom = true;
} }

View File

@ -75,7 +75,8 @@ import {
VariableStatement, VariableStatement,
decoratorNameToKind, decoratorNameToKind,
findDecorator findDecorator,
ExportDefaultStatement
} from "./ast"; } from "./ast";
import { import {
@ -100,10 +101,6 @@ import {
Flow Flow
} from "./flow"; } from "./flow";
import {
BuiltinSymbols
} from "./builtins";
/** Represents a yet unresolved `import`. */ /** Represents a yet unresolved `import`. */
class QueuedImport { class QueuedImport {
constructor( constructor(
@ -616,6 +613,10 @@ export class Program extends DiagnosticEmitter {
this.initializeExports(<ExportStatement>statement, file, queuedExports, queuedExportsStar); this.initializeExports(<ExportStatement>statement, file, queuedExports, queuedExportsStar);
break; break;
} }
case NodeKind.EXPORTDEFAULT: {
this.initializeExportDefault(<ExportDefaultStatement>statement, file, queuedExtends, queuedImplements);
break;
}
case NodeKind.IMPORT: { case NodeKind.IMPORT: {
this.initializeImports(<ImportStatement>statement, file, queuedImports, queuedExports); this.initializeImports(<ImportStatement>statement, file, queuedImports, queuedExports);
break; break;
@ -1117,7 +1118,7 @@ export class Program extends DiagnosticEmitter {
queuedExtends: ClassPrototype[], queuedExtends: ClassPrototype[],
/** So far queued `implements` clauses. */ /** So far queued `implements` clauses. */
queuedImplements: ClassPrototype[] queuedImplements: ClassPrototype[]
): void { ): ClassPrototype | null {
var name = declaration.name.text; var name = declaration.name.text;
var element = new ClassPrototype( var element = new ClassPrototype(
name, name,
@ -1129,7 +1130,7 @@ export class Program extends DiagnosticEmitter {
DecoratorFlags.UNMANAGED DecoratorFlags.UNMANAGED
) )
); );
if (!parent.add(name, element)) return; if (!parent.add(name, element)) return null;
var implementsTypes = declaration.implementsTypes; var implementsTypes = declaration.implementsTypes;
if (implementsTypes) { if (implementsTypes) {
@ -1180,6 +1181,7 @@ export class Program extends DiagnosticEmitter {
default: assert(false); // class member expected default: assert(false); // class member expected
} }
} }
return element;
} }
/** Initializes a field of a class or interface. */ /** Initializes a field of a class or interface. */
@ -1396,7 +1398,7 @@ export class Program extends DiagnosticEmitter {
declaration: EnumDeclaration, declaration: EnumDeclaration,
/** Parent element, usually a file or namespace. */ /** Parent element, usually a file or namespace. */
parent: Element parent: Element
): void { ): Enum | null {
var name = declaration.name.text; var name = declaration.name.text;
var element = new Enum( var element = new Enum(
name, name,
@ -1408,11 +1410,12 @@ export class Program extends DiagnosticEmitter {
DecoratorFlags.LAZY DecoratorFlags.LAZY
) )
); );
if (!parent.add(name, element)) return; if (!parent.add(name, element)) return null;
var values = declaration.values; var values = declaration.values;
for (let i = 0, k = values.length; i < k; ++i) { for (let i = 0, k = values.length; i < k; ++i) {
this.initializeEnumValue(values[i], element); this.initializeEnumValue(values[i], element);
} }
return element;
} }
/** Initializes an enum value. */ /** Initializes an enum value. */
@ -1523,6 +1526,55 @@ export class Program extends DiagnosticEmitter {
} }
} }
private initializeExportDefault(
/** The statement to initialize. */
statement: ExportDefaultStatement,
/** Parent file. */
parent: File,
/** So far queued `extends` clauses. */
queuedExtends: Array<ClassPrototype>,
/** So far queued `implements` clauses. */
queuedImplements: ClassPrototype[]
): void {
var declaration = statement.declaration;
var element: DeclaredElement | null = null;
switch (declaration.kind) {
case NodeKind.ENUMDECLARATION: {
element = this.initializeEnum(<EnumDeclaration>declaration, parent);
break;
}
case NodeKind.FUNCTIONDECLARATION: {
element = this.initializeFunction(<FunctionDeclaration>declaration, parent);
break;
}
case NodeKind.CLASSDECLARATION: {
element = this.initializeClass(<ClassDeclaration>declaration, parent, queuedExtends, queuedImplements);
break;
}
case NodeKind.INTERFACEDECLARATION: {
element = this.initializeInterface(<InterfaceDeclaration>declaration, parent);
break;
}
case NodeKind.NAMESPACEDECLARATION: {
element = this.initializeNamespace(<NamespaceDeclaration>declaration, parent, queuedExtends, queuedImplements);
break;
}
default: assert(false);
}
if (element) {
let exports = parent.exports;
if (!exports) parent.exports = exports = new Map();
else if (exports.has("default")) {
this.error(
DiagnosticCode.Duplicate_identifier_0,
declaration.name.range, "default"
)
return;
}
exports.set("default", element);
}
}
/** Initializes an `import` statement. */ /** Initializes an `import` statement. */
private initializeImports( private initializeImports(
/** The statement to initialize. */ /** The statement to initialize. */
@ -1531,7 +1583,7 @@ export class Program extends DiagnosticEmitter {
parent: File, parent: File,
/** So far queued `import`s. */ /** So far queued `import`s. */
queuedImports: QueuedImport[], queuedImports: QueuedImport[],
/** SO far queued `export`s. */ /** So far queued `export`s. */
queuedExports: Map<File,Map<string,QueuedExport>> queuedExports: Map<File,Map<string,QueuedExport>>
): void { ): void {
var declarations = statement.declarations; var declarations = statement.declarations;
@ -1598,7 +1650,7 @@ export class Program extends DiagnosticEmitter {
declaration: FunctionDeclaration, declaration: FunctionDeclaration,
/** Parent element, usually a file or namespace. */ /** Parent element, usually a file or namespace. */
parent: Element parent: Element
): void { ): FunctionPrototype | null {
var name = declaration.name.text; var name = declaration.name.text;
var validDecorators = DecoratorFlags.UNSAFE | DecoratorFlags.BUILTIN; var validDecorators = DecoratorFlags.UNSAFE | DecoratorFlags.BUILTIN;
if (declaration.is(CommonFlags.AMBIENT)) { if (declaration.is(CommonFlags.AMBIENT)) {
@ -1622,7 +1674,7 @@ export class Program extends DiagnosticEmitter {
declaration, declaration,
this.checkDecorators(declaration.decorators, validDecorators) this.checkDecorators(declaration.decorators, validDecorators)
); );
if (!parent.add(name, element)) return; if (!parent.add(name, element)) return null;
if (element.hasDecorator(DecoratorFlags.START)) { if (element.hasDecorator(DecoratorFlags.START)) {
if (this.explicitStartFunction) { if (this.explicitStartFunction) {
this.error( this.error(
@ -1631,6 +1683,7 @@ export class Program extends DiagnosticEmitter {
); );
} else this.explicitStartFunction = element; } else this.explicitStartFunction = element;
} }
return element;
} }
/** Initializes an interface. */ /** Initializes an interface. */
@ -1639,7 +1692,7 @@ export class Program extends DiagnosticEmitter {
declaration: InterfaceDeclaration, declaration: InterfaceDeclaration,
/** Parent element, usually a file or namespace. */ /** Parent element, usually a file or namespace. */
parent: Element parent: Element
): void { ): InterfacePrototype | null {
var name = declaration.name.text; var name = declaration.name.text;
var element = new InterfacePrototype( var element = new InterfacePrototype(
name, name,
@ -1649,7 +1702,7 @@ export class Program extends DiagnosticEmitter {
DecoratorFlags.GLOBAL DecoratorFlags.GLOBAL
) )
); );
if (!parent.add(name, element)) return; if (!parent.add(name, element)) return null;
var memberDeclarations = declaration.members; var memberDeclarations = declaration.members;
for (let i = 0, k = memberDeclarations.length; i < k; ++i) { for (let i = 0, k = memberDeclarations.length; i < k; ++i) {
let memberDeclaration = memberDeclarations[i]; let memberDeclaration = memberDeclarations[i];
@ -1669,6 +1722,7 @@ export class Program extends DiagnosticEmitter {
default: assert(false); // interface member expected default: assert(false); // interface member expected
} }
} }
return element;
} }
/** Initializes a namespace. */ /** Initializes a namespace. */
@ -1681,7 +1735,7 @@ export class Program extends DiagnosticEmitter {
queuedExtends: ClassPrototype[], queuedExtends: ClassPrototype[],
/** So far queued `implements` clauses. */ /** So far queued `implements` clauses. */
queuedImplements: ClassPrototype[] queuedImplements: ClassPrototype[]
): void { ): Namespace | null {
var name = declaration.name.text; var name = declaration.name.text;
var original = new Namespace( var original = new Namespace(
name, name,
@ -1689,7 +1743,7 @@ export class Program extends DiagnosticEmitter {
declaration, declaration,
this.checkDecorators(declaration.decorators, DecoratorFlags.GLOBAL) this.checkDecorators(declaration.decorators, DecoratorFlags.GLOBAL)
); );
if (!parent.add(name, original)) return; if (!parent.add(name, original)) return null;
var element = assert(parent.lookupInSelf(name)); // possibly merged var element = assert(parent.lookupInSelf(name)); // possibly merged
var members = declaration.members; var members = declaration.members;
for (let i = 0, k = members.length; i < k; ++i) { for (let i = 0, k = members.length; i < k; ++i) {
@ -1727,6 +1781,7 @@ export class Program extends DiagnosticEmitter {
} }
} }
if (original != element) copyMembers(original, element); // retain original parent if (original != element) copyMembers(original, element); // retain original parent
return element;
} }
/** Initializes a `type` definition. */ /** Initializes a `type` definition. */

View File

@ -1,6 +1,6 @@
{ {
"asc_flags": [ "asc_flags": [
"--runtime none", "--runtime half",
"--use ASC_RTRACE=1" "--use ASC_RTRACE=1"
] ]
} }

View File

@ -0,0 +1,5 @@
{
"asc_flags": [
"--runtime none"
]
}

View File

@ -0,0 +1,10 @@
(module
(type $FUNCSIG$v (func))
(memory $0 0)
(export "memory" (memory $0))
(export "theDefault" (func $export-default/theDefault))
(export "default" (func $export-default/theDefault))
(func $export-default/theDefault (; 0 ;) (type $FUNCSIG$v)
nop
)
)

View File

@ -0,0 +1 @@
export default function theDefault(): void {}

View File

@ -0,0 +1,14 @@
(module
(type $FUNCSIG$v (func))
(memory $0 0)
(table $0 1 funcref)
(elem (i32.const 0) $null)
(export "memory" (memory $0))
(export "theDefault" (func $export-default/theDefault))
(export "default" (func $export-default/theDefault))
(func $export-default/theDefault (; 0 ;) (type $FUNCSIG$v)
nop
)
(func $null (; 1 ;) (type $FUNCSIG$v)
)
)

View File

@ -13,6 +13,7 @@
(export "b" (global $export/b)) (export "b" (global $export/b))
(export "renamed_c" (global $export/c)) (export "renamed_c" (global $export/c))
(export "ns.two" (func $export/ns.one)) (export "ns.two" (func $export/ns.one))
(export "default.two" (func $export/ns.one))
(func $export/add (; 0 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) (func $export/add (; 0 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
local.get $0 local.get $0
local.get $1 local.get $1

View File

@ -28,3 +28,5 @@ export namespace ns {
function one(): void {} function one(): void {}
export function two(): void {} export function two(): void {}
} }
export default ns;

View File

@ -15,6 +15,7 @@
(export "b" (global $export/b)) (export "b" (global $export/b))
(export "renamed_c" (global $export/c)) (export "renamed_c" (global $export/c))
(export "ns.two" (func $export/ns.two)) (export "ns.two" (func $export/ns.two))
(export "default.two" (func $export/ns.two))
(func $export/add (; 0 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) (func $export/add (; 0 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
local.get $0 local.get $0
local.get $1 local.get $1

View File

@ -21,3 +21,11 @@ other.sub(other.b, other.renamed_c) +
other.renamed_mul(other.renamed_c, other.a); other.renamed_mul(other.renamed_c, other.a);
other.ns.two(); other.ns.two();
import theDefault from "./export";
theDefault.two();
import theOtherDefault from "./export-default";
theOtherDefault();

View File

@ -27,37 +27,42 @@
(func $export/ns.two (; 3 ;) (type $FUNCSIG$v) (func $export/ns.two (; 3 ;) (type $FUNCSIG$v)
nop nop
) )
(func $start:import (; 4 ;) (type $FUNCSIG$v) (func $export-default/theDefault (; 4 ;) (type $FUNCSIG$v)
global.get $export/a nop
global.get $export/b
call $export/add
global.get $export/b
global.get $export/c
call $export/sub
i32.add
global.get $export/c
global.get $export/a
call $export/mul
i32.add
drop
call $export/ns.two
global.get $export/a
global.get $export/b
call $export/add
global.get $export/b
global.get $export/c
call $export/sub
i32.add
global.get $export/c
global.get $export/a
call $export/mul
i32.add
drop
call $export/ns.two
) )
(func $start (; 5 ;) (type $FUNCSIG$v) (func $start:import (; 5 ;) (type $FUNCSIG$v)
global.get $export/a
global.get $export/b
call $export/add
global.get $export/b
global.get $export/c
call $export/sub
i32.add
global.get $export/c
global.get $export/a
call $export/mul
i32.add
drop
call $export/ns.two
global.get $export/a
global.get $export/b
call $export/add
global.get $export/b
global.get $export/c
call $export/sub
i32.add
global.get $export/c
global.get $export/a
call $export/mul
i32.add
drop
call $export/ns.two
call $export/ns.two
call $export-default/theDefault
)
(func $start (; 6 ;) (type $FUNCSIG$v)
call $start:import call $start:import
) )
(func $null (; 6 ;) (type $FUNCSIG$v) (func $null (; 7 ;) (type $FUNCSIG$v)
) )
) )

View File

@ -0,0 +1,6 @@
export default function theFunction(): void {}
export default class TheClass {}
// not so ts-y:
export default enum TheEnum {}
export default namespace theNamespace {}
export default something;

View File

@ -0,0 +1,7 @@
export default function theFunction(): void {}
export default class TheClass {}
export default enum TheEnum {}
export default namespace theNamespace {}
export {
something as default
};