mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Initial support for default imports/exports, see #98
Does not implement combinations like 'import theDefault, *' yet
This commit is contained in:
parent
27e54ed07b
commit
fa667386d9
@ -39,9 +39,6 @@
|
||||
"no-debugger": {
|
||||
"severity": "error"
|
||||
},
|
||||
"no-default-export": {
|
||||
"severity": "error"
|
||||
},
|
||||
"no-duplicate-super": {
|
||||
"severity": "error"
|
||||
},
|
||||
|
19
src/ast.ts
19
src/ast.ts
@ -67,6 +67,7 @@ export enum NodeKind {
|
||||
DO,
|
||||
EMPTY,
|
||||
EXPORT,
|
||||
EXPORTDEFAULT,
|
||||
EXPORTIMPORT,
|
||||
EXPRESSION,
|
||||
FOR,
|
||||
@ -701,6 +702,16 @@ export abstract class Node {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static createExportDefaultStatement(
|
||||
declaration: DeclarationStatement,
|
||||
range: Range
|
||||
): ExportDefaultStatement {
|
||||
var stmt = new ExportDefaultStatement();
|
||||
stmt.declaration = declaration;
|
||||
stmt.range = range;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static createExportImportStatement(
|
||||
name: IdentifierExpression,
|
||||
externalName: IdentifierExpression,
|
||||
@ -1775,6 +1786,14 @@ export class ExportStatement extends Statement {
|
||||
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. */
|
||||
export class ExpressionStatement extends Statement {
|
||||
kind = NodeKind.EXPRESSION;
|
||||
|
@ -156,7 +156,8 @@ import {
|
||||
|
||||
nodeIsConstantValue,
|
||||
findDecorator,
|
||||
isTypeOmitted
|
||||
isTypeOmitted,
|
||||
ExportDefaultStatement
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -1619,6 +1620,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// === Statements ===============================================================================
|
||||
|
||||
compileTopLevelStatement(statement: Statement, body: ExpressionRef[]): void {
|
||||
if (statement.kind == NodeKind.EXPORTDEFAULT) {
|
||||
statement = (<ExportDefaultStatement>statement).declaration;
|
||||
}
|
||||
switch (statement.kind) {
|
||||
case NodeKind.CLASSDECLARATION: {
|
||||
let memberStatements = (<ClassDeclaration>statement).members;
|
||||
|
@ -66,6 +66,7 @@ export enum DiagnosticCode {
|
||||
Type_expected = 1110,
|
||||
A_default_clause_cannot_appear_more_than_once_in_a_switch_statement = 1113,
|
||||
Duplicate_label_0 = 1114,
|
||||
An_export_assignment_cannot_have_modifiers = 1120,
|
||||
Octal_literals_are_not_allowed_in_strict_mode = 1121,
|
||||
Digit_expected = 1124,
|
||||
Hexadecimal_digit_expected = 1125,
|
||||
@ -204,6 +205,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 1110: return "Type expected.";
|
||||
case 1113: return "A 'default' clause cannot appear more than once in a 'switch' statement.";
|
||||
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 1124: return "Digit expected.";
|
||||
case 1125: return "Hexadecimal digit expected.";
|
||||
|
@ -59,6 +59,7 @@
|
||||
"Type expected.": 1110,
|
||||
"A 'default' clause cannot appear more than once in a 'switch' statement.": 1113,
|
||||
"Duplicate label '{0}'.": 1114,
|
||||
"An export assignment cannot have modifiers.": 1120,
|
||||
"Octal literals are not allowed in strict mode.": 1121,
|
||||
"Digit expected.": 1124,
|
||||
"Hexadecimal digit expected.": 1125,
|
||||
|
@ -52,6 +52,7 @@ import {
|
||||
EmptyStatement,
|
||||
ExportImportStatement,
|
||||
ExportStatement,
|
||||
ExportDefaultStatement,
|
||||
ExpressionStatement,
|
||||
ForStatement,
|
||||
IfStatement,
|
||||
@ -230,6 +231,10 @@ export class ASTBuilder {
|
||||
this.visitExportStatement(<ExportStatement>node);
|
||||
break;
|
||||
}
|
||||
case NodeKind.EXPORTDEFAULT: {
|
||||
this.visitExportDefaultStatement(<ExportDefaultStatement>node);
|
||||
break;
|
||||
}
|
||||
case NodeKind.EXPORTIMPORT: {
|
||||
this.visitExportImportStatement(<ExportImportStatement>node);
|
||||
break;
|
||||
@ -851,15 +856,19 @@ export class ASTBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
visitClassDeclaration(node: ClassDeclaration): void {
|
||||
visitClassDeclaration(node: ClassDeclaration, isDefault: bool = false): void {
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
this.serializeDecorator(decorators[i]);
|
||||
}
|
||||
}
|
||||
this.serializeExternalModifiers(node);
|
||||
var sb = this.sb;
|
||||
if (isDefault) {
|
||||
sb.push("export default ");
|
||||
} else {
|
||||
this.serializeExternalModifiers(node);
|
||||
}
|
||||
if (node.is(CommonFlags.ABSTRACT)) sb.push("abstract ");
|
||||
if (node.name.text.length) {
|
||||
sb.push("class ");
|
||||
@ -931,9 +940,13 @@ export class ASTBuilder {
|
||||
visitEmptyStatement(node: EmptyStatement): void {
|
||||
}
|
||||
|
||||
visitEnumDeclaration(node: EnumDeclaration): void {
|
||||
visitEnumDeclaration(node: EnumDeclaration, isDefault: bool = false): void {
|
||||
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 ");
|
||||
sb.push("enum ");
|
||||
this.visitIdentifierExpression(node.name);
|
||||
@ -1011,6 +1024,33 @@ export class ASTBuilder {
|
||||
sb.push(";");
|
||||
}
|
||||
|
||||
visitExportDefaultStatement(node: ExportDefaultStatement): void {
|
||||
var declaration = node.declaration;
|
||||
switch (declaration.kind) {
|
||||
case NodeKind.ENUMDECLARATION: {
|
||||
this.visitEnumDeclaration(<EnumDeclaration>declaration, true);
|
||||
break;
|
||||
}
|
||||
case NodeKind.FUNCTIONDECLARATION: {
|
||||
this.visitFunctionDeclaration(<FunctionDeclaration>declaration, true);
|
||||
break;
|
||||
}
|
||||
case NodeKind.CLASSDECLARATION: {
|
||||
this.visitClassDeclaration(<ClassDeclaration>declaration, true);
|
||||
break;
|
||||
}
|
||||
case NodeKind.INTERFACEDECLARATION: {
|
||||
this.visitInterfaceDeclaration(<InterfaceDeclaration>declaration, true);
|
||||
break;
|
||||
}
|
||||
case NodeKind.NAMESPACEDECLARATION: {
|
||||
this.visitNamespaceDeclaration(<NamespaceDeclaration>declaration, true);
|
||||
break;
|
||||
}
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
visitExpressionStatement(node: ExpressionStatement): void {
|
||||
this.visitNode(node.expression);
|
||||
}
|
||||
@ -1065,7 +1105,7 @@ export class ASTBuilder {
|
||||
this.visitNode(node.statement);
|
||||
}
|
||||
|
||||
visitFunctionDeclaration(node: FunctionDeclaration): void {
|
||||
visitFunctionDeclaration(node: FunctionDeclaration, isDefault: bool = false): void {
|
||||
var sb = this.sb;
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
@ -1073,8 +1113,12 @@ export class ASTBuilder {
|
||||
this.serializeDecorator(decorators[i]);
|
||||
}
|
||||
}
|
||||
this.serializeExternalModifiers(node);
|
||||
this.serializeAccessModifiers(node);
|
||||
if (isDefault) {
|
||||
sb.push("export default ");
|
||||
} else {
|
||||
this.serializeExternalModifiers(node);
|
||||
this.serializeAccessModifiers(node);
|
||||
}
|
||||
if (node.name.text.length) {
|
||||
sb.push("function ");
|
||||
} else {
|
||||
@ -1230,15 +1274,19 @@ export class ASTBuilder {
|
||||
this.visitTypeNode(node.valueType);
|
||||
}
|
||||
|
||||
visitInterfaceDeclaration(node: InterfaceDeclaration): void {
|
||||
visitInterfaceDeclaration(node: InterfaceDeclaration, isDefault: bool = false): void {
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
this.serializeDecorator(decorators[i]);
|
||||
}
|
||||
}
|
||||
this.serializeExternalModifiers(node);
|
||||
var sb = this.sb;
|
||||
if (isDefault) {
|
||||
sb.push("export default ");
|
||||
} else {
|
||||
this.serializeExternalModifiers(node);
|
||||
}
|
||||
sb.push("interface ");
|
||||
this.visitIdentifierExpression(node.name);
|
||||
var typeParameters = node.typeParameters;
|
||||
@ -1284,15 +1332,19 @@ export class ASTBuilder {
|
||||
this.visitFunctionCommon(node);
|
||||
}
|
||||
|
||||
visitNamespaceDeclaration(node: NamespaceDeclaration): void {
|
||||
visitNamespaceDeclaration(node: NamespaceDeclaration, isDefault: bool = false): void {
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
this.serializeDecorator(decorators[i]);
|
||||
}
|
||||
}
|
||||
this.serializeExternalModifiers(node);
|
||||
var sb = this.sb;
|
||||
if (isDefault) {
|
||||
sb.push("export default ");
|
||||
} else {
|
||||
this.serializeExternalModifiers(node);
|
||||
}
|
||||
sb.push("namespace ");
|
||||
this.visitIdentifierExpression(node.name);
|
||||
var members = node.members;
|
||||
|
@ -171,31 +171,34 @@ export class Parser extends DiagnosticEmitter {
|
||||
// check modifiers
|
||||
var exportStart: i32 = 0;
|
||||
var exportEnd: i32 = 0;
|
||||
var defaultStart: i32 = 0;
|
||||
var defaultEnd: i32 = 0;
|
||||
if (tn.skip(Token.EXPORT)) {
|
||||
if (tn.skip(Token.DEFAULT)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
tn.range()
|
||||
);
|
||||
}
|
||||
if (startPos < 0) startPos = tn.tokenPos;
|
||||
flags |= CommonFlags.EXPORT;
|
||||
exportStart = tn.tokenPos;
|
||||
exportEnd = tn.pos;
|
||||
if (tn.skip(Token.DEFAULT)) {
|
||||
defaultStart = tn.tokenPos;
|
||||
defaultEnd = tn.pos;
|
||||
}
|
||||
}
|
||||
|
||||
var declareStart: i32 = 0;
|
||||
var declareEnd: i32 = 0;
|
||||
var contextIsAmbient = namespace != null && namespace.is(CommonFlags.AMBIENT);
|
||||
if (tn.skip(Token.DECLARE)) {
|
||||
if (startPos < 0) startPos = tn.tokenPos;
|
||||
if (contextIsAmbient) {
|
||||
this.error(
|
||||
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
|
||||
tn.range()
|
||||
); // 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) {
|
||||
flags |= CommonFlags.AMBIENT;
|
||||
}
|
||||
@ -297,7 +300,18 @@ export class Parser extends DiagnosticEmitter {
|
||||
|
||||
// handle plain exports
|
||||
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
|
||||
} 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;
|
||||
}
|
||||
|
||||
@ -2318,6 +2351,28 @@ export class Parser extends DiagnosticEmitter {
|
||||
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(
|
||||
tn: Tokenizer
|
||||
): ImportStatement | null {
|
||||
@ -2330,7 +2385,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
var members: ImportDeclaration[] | null = null;
|
||||
var namespaceName: IdentifierExpression | null = null;
|
||||
var skipFrom = false;
|
||||
if (tn.skip(Token.OPENBRACE)) {
|
||||
if (tn.skip(Token.OPENBRACE)) { // import { ... } from "file"
|
||||
members = new Array();
|
||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
||||
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.skipIdentifier()) {
|
||||
namespaceName = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
|
||||
@ -2366,7 +2421,25 @@ export class Parser extends DiagnosticEmitter {
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,8 @@ import {
|
||||
VariableStatement,
|
||||
|
||||
decoratorNameToKind,
|
||||
findDecorator
|
||||
findDecorator,
|
||||
ExportDefaultStatement
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -100,10 +101,6 @@ import {
|
||||
Flow
|
||||
} from "./flow";
|
||||
|
||||
import {
|
||||
BuiltinSymbols
|
||||
} from "./builtins";
|
||||
|
||||
/** Represents a yet unresolved `import`. */
|
||||
class QueuedImport {
|
||||
constructor(
|
||||
@ -616,6 +613,10 @@ export class Program extends DiagnosticEmitter {
|
||||
this.initializeExports(<ExportStatement>statement, file, queuedExports, queuedExportsStar);
|
||||
break;
|
||||
}
|
||||
case NodeKind.EXPORTDEFAULT: {
|
||||
this.initializeExportDefault(<ExportDefaultStatement>statement, file, queuedExtends, queuedImplements);
|
||||
break;
|
||||
}
|
||||
case NodeKind.IMPORT: {
|
||||
this.initializeImports(<ImportStatement>statement, file, queuedImports, queuedExports);
|
||||
break;
|
||||
@ -1117,7 +1118,7 @@ export class Program extends DiagnosticEmitter {
|
||||
queuedExtends: ClassPrototype[],
|
||||
/** So far queued `implements` clauses. */
|
||||
queuedImplements: ClassPrototype[]
|
||||
): void {
|
||||
): ClassPrototype | null {
|
||||
var name = declaration.name.text;
|
||||
var element = new ClassPrototype(
|
||||
name,
|
||||
@ -1129,7 +1130,7 @@ export class Program extends DiagnosticEmitter {
|
||||
DecoratorFlags.UNMANAGED
|
||||
)
|
||||
);
|
||||
if (!parent.add(name, element)) return;
|
||||
if (!parent.add(name, element)) return null;
|
||||
|
||||
var implementsTypes = declaration.implementsTypes;
|
||||
if (implementsTypes) {
|
||||
@ -1180,6 +1181,7 @@ export class Program extends DiagnosticEmitter {
|
||||
default: assert(false); // class member expected
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Initializes a field of a class or interface. */
|
||||
@ -1396,7 +1398,7 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration: EnumDeclaration,
|
||||
/** Parent element, usually a file or namespace. */
|
||||
parent: Element
|
||||
): void {
|
||||
): Enum | null {
|
||||
var name = declaration.name.text;
|
||||
var element = new Enum(
|
||||
name,
|
||||
@ -1408,11 +1410,12 @@ export class Program extends DiagnosticEmitter {
|
||||
DecoratorFlags.LAZY
|
||||
)
|
||||
);
|
||||
if (!parent.add(name, element)) return;
|
||||
if (!parent.add(name, element)) return null;
|
||||
var values = declaration.values;
|
||||
for (let i = 0, k = values.length; i < k; ++i) {
|
||||
this.initializeEnumValue(values[i], element);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
private initializeImports(
|
||||
/** The statement to initialize. */
|
||||
@ -1531,7 +1583,7 @@ export class Program extends DiagnosticEmitter {
|
||||
parent: File,
|
||||
/** So far queued `import`s. */
|
||||
queuedImports: QueuedImport[],
|
||||
/** SO far queued `export`s. */
|
||||
/** So far queued `export`s. */
|
||||
queuedExports: Map<File,Map<string,QueuedExport>>
|
||||
): void {
|
||||
var declarations = statement.declarations;
|
||||
@ -1598,7 +1650,7 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration: FunctionDeclaration,
|
||||
/** Parent element, usually a file or namespace. */
|
||||
parent: Element
|
||||
): void {
|
||||
): FunctionPrototype | null {
|
||||
var name = declaration.name.text;
|
||||
var validDecorators = DecoratorFlags.UNSAFE | DecoratorFlags.BUILTIN;
|
||||
if (declaration.is(CommonFlags.AMBIENT)) {
|
||||
@ -1622,7 +1674,7 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration,
|
||||
this.checkDecorators(declaration.decorators, validDecorators)
|
||||
);
|
||||
if (!parent.add(name, element)) return;
|
||||
if (!parent.add(name, element)) return null;
|
||||
if (element.hasDecorator(DecoratorFlags.START)) {
|
||||
if (this.explicitStartFunction) {
|
||||
this.error(
|
||||
@ -1631,6 +1683,7 @@ export class Program extends DiagnosticEmitter {
|
||||
);
|
||||
} else this.explicitStartFunction = element;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Initializes an interface. */
|
||||
@ -1639,7 +1692,7 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration: InterfaceDeclaration,
|
||||
/** Parent element, usually a file or namespace. */
|
||||
parent: Element
|
||||
): void {
|
||||
): InterfacePrototype | null {
|
||||
var name = declaration.name.text;
|
||||
var element = new InterfacePrototype(
|
||||
name,
|
||||
@ -1649,7 +1702,7 @@ export class Program extends DiagnosticEmitter {
|
||||
DecoratorFlags.GLOBAL
|
||||
)
|
||||
);
|
||||
if (!parent.add(name, element)) return;
|
||||
if (!parent.add(name, element)) return null;
|
||||
var memberDeclarations = declaration.members;
|
||||
for (let i = 0, k = memberDeclarations.length; i < k; ++i) {
|
||||
let memberDeclaration = memberDeclarations[i];
|
||||
@ -1669,6 +1722,7 @@ export class Program extends DiagnosticEmitter {
|
||||
default: assert(false); // interface member expected
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Initializes a namespace. */
|
||||
@ -1681,7 +1735,7 @@ export class Program extends DiagnosticEmitter {
|
||||
queuedExtends: ClassPrototype[],
|
||||
/** So far queued `implements` clauses. */
|
||||
queuedImplements: ClassPrototype[]
|
||||
): void {
|
||||
): Namespace | null {
|
||||
var name = declaration.name.text;
|
||||
var original = new Namespace(
|
||||
name,
|
||||
@ -1689,7 +1743,7 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration,
|
||||
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 members = declaration.members;
|
||||
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
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Initializes a `type` definition. */
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"asc_flags": [
|
||||
"--runtime none",
|
||||
"--runtime half",
|
||||
"--use ASC_RTRACE=1"
|
||||
]
|
||||
}
|
||||
|
5
tests/compiler/export-default.json
Normal file
5
tests/compiler/export-default.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"asc_flags": [
|
||||
"--runtime none"
|
||||
]
|
||||
}
|
10
tests/compiler/export-default.optimized.wat
Normal file
10
tests/compiler/export-default.optimized.wat
Normal 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
|
||||
)
|
||||
)
|
1
tests/compiler/export-default.ts
Normal file
1
tests/compiler/export-default.ts
Normal file
@ -0,0 +1 @@
|
||||
export default function theDefault(): void {}
|
14
tests/compiler/export-default.untouched.wat
Normal file
14
tests/compiler/export-default.untouched.wat
Normal 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)
|
||||
)
|
||||
)
|
@ -13,6 +13,7 @@
|
||||
(export "b" (global $export/b))
|
||||
(export "renamed_c" (global $export/c))
|
||||
(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)
|
||||
local.get $0
|
||||
local.get $1
|
||||
|
@ -28,3 +28,5 @@ export namespace ns {
|
||||
function one(): void {}
|
||||
export function two(): void {}
|
||||
}
|
||||
|
||||
export default ns;
|
||||
|
@ -15,6 +15,7 @@
|
||||
(export "b" (global $export/b))
|
||||
(export "renamed_c" (global $export/c))
|
||||
(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)
|
||||
local.get $0
|
||||
local.get $1
|
||||
|
@ -21,3 +21,11 @@ other.sub(other.b, other.renamed_c) +
|
||||
other.renamed_mul(other.renamed_c, other.a);
|
||||
|
||||
other.ns.two();
|
||||
|
||||
import theDefault from "./export";
|
||||
|
||||
theDefault.two();
|
||||
|
||||
import theOtherDefault from "./export-default";
|
||||
|
||||
theOtherDefault();
|
||||
|
@ -27,37 +27,42 @@
|
||||
(func $export/ns.two (; 3 ;) (type $FUNCSIG$v)
|
||||
nop
|
||||
)
|
||||
(func $start:import (; 4 ;) (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
|
||||
(func $export-default/theDefault (; 4 ;) (type $FUNCSIG$v)
|
||||
nop
|
||||
)
|
||||
(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
|
||||
)
|
||||
(func $null (; 6 ;) (type $FUNCSIG$v)
|
||||
(func $null (; 7 ;) (type $FUNCSIG$v)
|
||||
)
|
||||
)
|
||||
|
6
tests/parser/export-default.ts
Normal file
6
tests/parser/export-default.ts
Normal 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;
|
7
tests/parser/export-default.ts.fixture.ts
Normal file
7
tests/parser/export-default.ts.fixture.ts
Normal 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
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user