Fix external names of class exports and similar; Support a few more kinds in TSDBuilder, see #74

This commit is contained in:
dcodeIO 2018-04-15 00:34:19 +02:00
parent 78a679759a
commit 81223977d0
15 changed files with 713 additions and 202 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@ import {
compileCall as compileBuiltinCall, compileCall as compileBuiltinCall,
compileGetConstant as compileBuiltinGetConstant, compileGetConstant as compileBuiltinGetConstant,
compileAllocate as compileBuiltinAllocate, compileAllocate as compileBuiltinAllocate,
compileAbort compileAbort as compileBuiltinAbort
} from "./builtins"; } from "./builtins";
import { import {
@ -32,6 +32,7 @@ import {
Program, Program,
ClassPrototype, ClassPrototype,
Class, Class,
Element,
ElementKind, ElementKind,
Enum, Enum,
Field, Field,
@ -52,7 +53,11 @@ import {
DecoratorFlags, DecoratorFlags,
PATH_DELIMITER, PATH_DELIMITER,
INNER_DELIMITER INNER_DELIMITER,
INSTANCE_DELIMITER,
STATIC_DELIMITER,
GETTER_PREFIX,
SETTER_PREFIX
} from "./program"; } from "./program";
import { import {
@ -272,10 +277,14 @@ export class Compiler extends DiagnosticEmitter {
// compile the start function if not empty // compile the start function if not empty
var startFunctionBody = this.startFunctionBody; var startFunctionBody = this.startFunctionBody;
if (startFunctionBody.length) { if (startFunctionBody.length) {
let typeRef = this.ensureFunctionType(startFunctionInstance.signature); let signature = startFunctionInstance.signature;
let funcRef = module.addFunction( let funcRef = module.addFunction(
startFunctionInstance.internalName, startFunctionInstance.internalName,
typeRef, this.ensureFunctionType(
signature.parameterTypes,
signature.returnType,
signature.thisType
),
typesToNativeTypes(startFunctionInstance.additionalLocals), typesToNativeTypes(startFunctionInstance.additionalLocals),
module.createBlock(null, startFunctionBody) module.createBlock(null, startFunctionBody)
); );
@ -510,8 +519,8 @@ export class Compiler extends DiagnosticEmitter {
global.set(CommonFlags.MODULE_IMPORT); global.set(CommonFlags.MODULE_IMPORT);
module.addGlobalImport( module.addGlobalImport(
global.internalName, global.internalName,
global.namespace global.parent
? global.namespace.simpleName ? global.parent.simpleName
: "env", : "env",
global.simpleName, global.simpleName,
nativeType nativeType
@ -609,21 +618,15 @@ export class Compiler extends DiagnosticEmitter {
DiagnosticCode.Operation_not_supported, DiagnosticCode.Operation_not_supported,
assert(global.declaration).range assert(global.declaration).range
); );
global.constantValueKind = ConstantValueKind.INTEGER; return false;
global.constantIntegerValue = i64_new(0);
break;
} }
} }
global.set(CommonFlags.INLINED); // inline the value from now on global.set(CommonFlags.INLINED); // inline the value from now on
if (declaration) { if (global.is(CommonFlags.MODULE_EXPORT)) {
if (declaration.isTopLevel) { // but keep the element as it might be re-exported module.addGlobal(internalName, nativeType, false, initExpr);
module.addGlobalExport(internalName, mangleExportName(global));
} else if (declaration && declaration.isTopLevel) { // might become re-exported
module.addGlobal(internalName, nativeType, false, initExpr); module.addGlobal(internalName, nativeType, false, initExpr);
}
if (declaration.range.source.isEntry && declaration.isTopLevelExport) {
module.addGlobalExport(global.internalName, declaration.programLevelInternalName);
}
} else {
assert(false); // must have a declaration if constant
} }
} else /* mutable */ { } else /* mutable */ {
@ -726,9 +729,9 @@ export class Compiler extends DiagnosticEmitter {
previousValue = <EnumValue>val; previousValue = <EnumValue>val;
// export values if the enum is exported // export values if the enum is exported
if (element.declaration.range.source.isEntry && element.declaration.isTopLevelExport) { if (element.is(CommonFlags.MODULE_EXPORT)) {
if (member.is(CommonFlags.INLINED)) { if (member.is(CommonFlags.INLINED)) {
module.addGlobalExport(member.internalName, member.internalName); module.addGlobalExport(member.internalName, mangleExportName(member));
} else if (valueDeclaration) { } else if (valueDeclaration) {
this.warning( this.warning(
DiagnosticCode.Cannot_export_a_mutable_global, DiagnosticCode.Cannot_export_a_mutable_global,
@ -781,10 +784,12 @@ export class Compiler extends DiagnosticEmitter {
} }
/** Either reuses or creates the function type matching the specified signature. */ /** Either reuses or creates the function type matching the specified signature. */
private ensureFunctionType(signature: Signature): FunctionTypeRef { private ensureFunctionType(
var parameters = signature.parameterTypes; parameterTypes: Type[] | null,
var numParameters = parameters.length; returnType: Type,
var thisType = signature.thisType; thisType: Type | null = null
): FunctionTypeRef {
var numParameters = parameterTypes ? parameterTypes.length : 0;
var paramTypes: NativeType[]; var paramTypes: NativeType[];
var index = 0; var index = 0;
if (thisType) { if (thisType) {
@ -794,14 +799,17 @@ export class Compiler extends DiagnosticEmitter {
} else { } else {
paramTypes = new Array(numParameters); paramTypes = new Array(numParameters);
} }
if (parameterTypes) {
for (let i = 0; i < numParameters; ++i, ++index) { for (let i = 0; i < numParameters; ++i, ++index) {
paramTypes[index] = signature.parameterTypes[i].toNativeType(); paramTypes[index] = parameterTypes[i].toNativeType();
} }
var resultType = signature.returnType.toNativeType(); }
var resultType = returnType.toNativeType();
var module = this.module; var module = this.module;
var typeRef = module.getFunctionTypeBySignature(resultType, paramTypes); var typeRef = module.getFunctionTypeBySignature(resultType, paramTypes);
if (!typeRef) { if (!typeRef) {
typeRef = module.addFunctionType(signature.toSignatureString(), resultType, paramTypes); let name = Signature.makeSignatureString(parameterTypes, returnType, thisType);
typeRef = module.addFunctionType(name, resultType, paramTypes);
} }
return typeRef; return typeRef;
} }
@ -832,7 +840,8 @@ export class Compiler extends DiagnosticEmitter {
} }
var ref: FunctionRef; var ref: FunctionRef;
var typeRef = this.ensureFunctionType(instance.signature); var signature = instance.signature;
var typeRef = this.ensureFunctionType(signature.parameterTypes, signature.returnType, signature.thisType);
var module = this.module; var module = this.module;
if (body) { if (body) {
let isConstructor = instance.is(CommonFlags.CONSTRUCTOR); let isConstructor = instance.is(CommonFlags.CONSTRUCTOR);
@ -868,7 +877,7 @@ export class Compiler extends DiagnosticEmitter {
// if not all branches are guaranteed to allocate, also append a conditional allocation // if not all branches are guaranteed to allocate, also append a conditional allocation
} else { } else {
let parent = assert(instance.memberOf); let parent = assert(instance.parent);
assert(parent.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
stmt = module.createBlock(null, [ stmt = module.createBlock(null, [
stmt, stmt,
@ -901,11 +910,11 @@ export class Compiler extends DiagnosticEmitter {
instance.set(CommonFlags.MODULE_IMPORT); instance.set(CommonFlags.MODULE_IMPORT);
// create the function import // create the function import
let namespace = instance.prototype.namespace; let parent = instance.prototype.parent;
ref = module.addFunctionImport( ref = module.addFunctionImport(
instance.internalName, instance.internalName,
namespace parent
? namespace.simpleName ? parent.simpleName
: "env", : "env",
instance.simpleName, instance.simpleName,
typeRef typeRef
@ -913,8 +922,8 @@ export class Compiler extends DiagnosticEmitter {
} }
// check module-level export // check module-level export
if (declaration.range.source.isEntry && declaration.isTopLevelExport) { if (instance.is(CommonFlags.MODULE_EXPORT)) {
module.addFunctionExport(instance.internalName, declaration.name.text); module.addFunctionExport(instance.internalName, mangleExportName(instance));
} }
instance.finalize(module, ref); instance.finalize(module, ref);
@ -1143,6 +1152,133 @@ export class Compiler extends DiagnosticEmitter {
compileClass(instance: Class): bool { compileClass(instance: Class): bool {
if (instance.is(CommonFlags.COMPILED)) return true; if (instance.is(CommonFlags.COMPILED)) return true;
instance.set(CommonFlags.COMPILED); instance.set(CommonFlags.COMPILED);
var staticMembers = instance.prototype.members;
if (staticMembers) {
for (let element of staticMembers.values()) {
switch (element.kind) {
case ElementKind.GLOBAL: {
this.compileGlobal(<Global>element);
break;
}
case ElementKind.FUNCTION_PROTOTYPE: {
if (
!(<FunctionPrototype>element).is(CommonFlags.GENERIC)
) {
this.compileFunctionUsingTypeArguments(
<FunctionPrototype>element,
[], null, null,
(<FunctionPrototype>element).declaration.name
);
}
break;
}
case ElementKind.PROPERTY: {
let getter = (<Property>element).getterPrototype;
if (getter) {
this.compileFunctionUsingTypeArguments(
getter,
[], null, null,
getter.declaration.name
);
}
let setter = (<Property>element).setterPrototype;
if (setter) {
this.compileFunctionUsingTypeArguments(
setter,
[], null, null,
setter.declaration.name
);
}
break;
}
}
}
}
var instanceMembers = instance.members;
if (instanceMembers) {
for (let element of instanceMembers.values()) {
switch (element.kind) {
case ElementKind.FUNCTION_PROTOTYPE: {
if (
!(<FunctionPrototype>element).is(CommonFlags.GENERIC)
) {
this.compileFunctionUsingTypeArguments(
<FunctionPrototype>element,
[],
instance.contextualTypeArguments,
null, // no outer scope
(<FunctionPrototype>element).declaration.name
);
}
break;
}
case ElementKind.FIELD: {
element.set(CommonFlags.COMPILED);
if (!instance.is(CommonFlags.MODULE_EXPORT) || element.is(CommonFlags.PRIVATE)) break;
let module = this.module;
let name = (<Field>element).simpleName;
let type = (<Field>element).type;
let nativeType = type.toNativeType();
let offset = (<Field>element).memoryOffset;
let usizeType = this.options.usizeType;
let nativeSizeType = this.options.nativeSizeType;
// export an implicit getter: get:fieldName(this: usize) -> fieldType
let getterName = mangleExportName(element, GETTER_PREFIX + name);
module.addFunction(
getterName,
this.ensureFunctionType(null, type, usizeType),
null,
module.createLoad(
type.byteSize,
type.is(TypeFlags.SIGNED),
module.createGetLocal(0, nativeSizeType),
nativeType,
offset
)
);
module.addFunctionExport(getterName, getterName);
// export an implicit setter: set:fieldName(this: usize, value: fieldType) -> void
if (element.is(CommonFlags.READONLY)) break;
let setterName = mangleExportName(element, SETTER_PREFIX + name);
module.addFunction(
setterName,
this.ensureFunctionType([ type ], Type.void, usizeType),
null,
module.createStore(
type.byteSize,
module.createGetLocal(0, nativeSizeType),
module.createGetLocal(1, nativeType),
nativeType,
offset
)
);
module.addFunctionExport(setterName, setterName);
break;
}
case ElementKind.PROPERTY: {
let getter = (<Property>element).getterPrototype;
if (getter) {
this.compileFunctionUsingTypeArguments(
getter,
[], instance.contextualTypeArguments, null,
getter.declaration.name
);
}
let setter = (<Property>element).setterPrototype;
if (setter) {
this.compileFunctionUsingTypeArguments(
setter,
[], instance.contextualTypeArguments, null,
setter.declaration.name
);
}
break;
}
}
}
}
return true; return true;
} }
@ -1672,7 +1808,7 @@ export class Compiler extends DiagnosticEmitter {
flow.set(FlowFlags.RETURNS); flow.set(FlowFlags.RETURNS);
// TODO: requires exception-handling spec. // TODO: requires exception-handling spec.
return compileAbort(this, null, statement); return compileBuiltinAbort(this, null, statement);
} }
compileTryStatement(statement: TryStatement): ExpressionRef { compileTryStatement(statement: TryStatement): ExpressionRef {
@ -4060,9 +4196,9 @@ export class Compiler extends DiagnosticEmitter {
var argumentExpressions: Expression[]; var argumentExpressions: Expression[];
var thisArg: ExpressionRef = 0; var thisArg: ExpressionRef = 0;
if (operatorInstance.is(CommonFlags.INSTANCE)) { if (operatorInstance.is(CommonFlags.INSTANCE)) {
let classElement = assert(operatorInstance.memberOf); let parent = assert(operatorInstance.parent);
assert(classElement.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
thisArg = this.compileExpression(value, (<Class>classElement).type); thisArg = this.compileExpression(value, (<Class>parent).type);
argumentExpressions = []; argumentExpressions = [];
} else { } else {
argumentExpressions = [ value ]; argumentExpressions = [ value ];
@ -4086,9 +4222,9 @@ export class Compiler extends DiagnosticEmitter {
var argumentExpressions: Expression[]; var argumentExpressions: Expression[];
var thisArg: ExpressionRef = 0; var thisArg: ExpressionRef = 0;
if (operatorInstance.is(CommonFlags.INSTANCE)) { if (operatorInstance.is(CommonFlags.INSTANCE)) {
let classElement = assert(operatorInstance.memberOf); let parent = assert(operatorInstance.parent);
assert(classElement.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
thisArg = this.compileExpression(left, (<Class>classElement).type); thisArg = this.compileExpression(left, (<Class>parent).type);
argumentExpressions = [ right ]; argumentExpressions = [ right ];
} else { } else {
argumentExpressions = [ left, right ]; argumentExpressions = [ left, right ];
@ -4755,9 +4891,9 @@ export class Compiler extends DiagnosticEmitter {
// here, with their respective locals being blocked. There is no 'makeCallInline'. // here, with their respective locals being blocked. There is no 'makeCallInline'.
var body = []; var body = [];
if (thisArg) { if (thisArg) {
let classElement = assert(instance.memberOf); let parent = assert(instance.parent);
assert(classElement.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
let thisLocal = flow.addScopedLocal((<Class>classElement).type, "this"); let thisLocal = flow.addScopedLocal((<Class>parent).type, "this");
body.push( body.push(
module.createSetLocal(thisLocal.index, thisArg) module.createSetLocal(thisLocal.index, thisArg)
); );
@ -4879,7 +5015,7 @@ export class Compiler extends DiagnosticEmitter {
original.prototype, original.prototype,
trampolineName, trampolineName,
trampolineSignature, trampolineSignature,
original.memberOf, original.parent,
original.contextualTypeArguments original.contextualTypeArguments
); );
trampoline.set(original.flags | CommonFlags.TRAMPOLINE | CommonFlags.COMPILED); trampoline.set(original.flags | CommonFlags.TRAMPOLINE | CommonFlags.COMPILED);
@ -4929,8 +5065,14 @@ export class Compiler extends DiagnosticEmitter {
this.currentFunction = previousFunction; this.currentFunction = previousFunction;
assert(operandIndex == maxOperands); assert(operandIndex == maxOperands);
var typeRef = this.ensureFunctionType(trampolineSignature); var funcRef = module.addFunction(
var funcRef = module.addFunction(trampolineName, typeRef, typesToNativeTypes(trampoline.additionalLocals), trampolineName,
this.ensureFunctionType(
trampolineSignature.parameterTypes,
trampolineSignature.returnType,
trampolineSignature.thisType
),
typesToNativeTypes(trampoline.additionalLocals),
module.createBlock(null, [ module.createBlock(null, [
body, body,
module.createCall( module.createCall(
@ -5052,7 +5194,7 @@ export class Compiler extends DiagnosticEmitter {
} }
assert(numOperands >= minOperands); assert(numOperands >= minOperands);
this.ensureFunctionType(signature); this.ensureFunctionType(signature.parameterTypes, signature.returnType, signature.thisType);
var module = this.module; var module = this.module;
// fill up omitted arguments with zeroes // fill up omitted arguments with zeroes
@ -5200,7 +5342,7 @@ export class Compiler extends DiagnosticEmitter {
} }
} }
if (currentFunction.is(CommonFlags.INSTANCE)) { if (currentFunction.is(CommonFlags.INSTANCE)) {
let parent = assert(currentFunction.memberOf); let parent = assert(currentFunction.parent);
assert(parent.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
let thisType = (<Class>parent).type; let thisType = (<Class>parent).type;
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) { if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
@ -5238,7 +5380,7 @@ export class Compiler extends DiagnosticEmitter {
} }
} }
if (currentFunction.is(CommonFlags.INSTANCE)) { if (currentFunction.is(CommonFlags.INSTANCE)) {
let parent = assert(currentFunction.memberOf); let parent = assert(currentFunction.parent);
assert(parent.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
let base = (<Class>parent).base; let base = (<Class>parent).base;
if (base) { if (base) {
@ -5759,7 +5901,9 @@ export class Compiler extends DiagnosticEmitter {
return module.createGetGlobal((<Global>target).internalName, globalType.toNativeType()); return module.createGetGlobal((<Global>target).internalName, globalType.toNativeType());
} }
case ElementKind.ENUMVALUE: { // enum value case ElementKind.ENUMVALUE: { // enum value
if (!this.compileEnum((<EnumValue>target).enum)) { let parent = (<EnumValue>target).parent;
assert(parent !== null && parent.kind == ElementKind.ENUM);
if (!this.compileEnum(<Enum>parent)) {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
this.currentType = Type.i32; this.currentType = Type.i32;
@ -5777,7 +5921,7 @@ export class Compiler extends DiagnosticEmitter {
); );
this.currentType = (<Field>target).type; this.currentType = (<Field>target).type;
return module.createLoad( return module.createLoad(
(<Field>target).type.size >> 3, (<Field>target).type.byteSize,
(<Field>target).type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), (<Field>target).type.is(TypeFlags.SIGNED | TypeFlags.INTEGER),
thisExpr, thisExpr,
(<Field>target).type.toNativeType(), (<Field>target).type.toNativeType(),
@ -5799,7 +5943,7 @@ export class Compiler extends DiagnosticEmitter {
return module.createUnreachable(); return module.createUnreachable();
} }
if (instance.is(CommonFlags.INSTANCE)) { if (instance.is(CommonFlags.INSTANCE)) {
let parent = assert(instance.memberOf); let parent = assert(instance.parent);
assert(parent.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
let thisExpression = assert(program.resolvedThisExpression); let thisExpression = assert(program.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType( let thisExpr = this.compileExpressionRetainType(
@ -6420,6 +6564,50 @@ export class Compiler extends DiagnosticEmitter {
// helpers // helpers
function mangleExportName(element: Element, explicitSimpleName: string | null = null): string {
var simpleName = explicitSimpleName != null
? explicitSimpleName
: element.simpleName;
switch (element.kind) {
case ElementKind.FUNCTION: {
let parent = (<Function>element).parent || (<Function>element).prototype.parent;
return parent
? mangleExportName(parent)
+ (element.is(CommonFlags.INSTANCE) ? INSTANCE_DELIMITER : STATIC_DELIMITER)
+ simpleName
: simpleName;
}
case ElementKind.FIELD: {
let parent = assert((<Field>element).parent);
return mangleExportName(parent)
+ (element.is(CommonFlags.INSTANCE) ? INSTANCE_DELIMITER : STATIC_DELIMITER)
+ simpleName;
}
case ElementKind.ENUMVALUE: {
let parent = assert((<EnumValue>element).parent);
return mangleExportName(parent)
+ (element.is(CommonFlags.INSTANCE) ? INSTANCE_DELIMITER : STATIC_DELIMITER)
+ simpleName;
}
case ElementKind.CLASS: {
let parent = (<Class>element).prototype.parent;
return parent
? mangleExportName(parent)
+ STATIC_DELIMITER
+ simpleName
: simpleName;
}
default: {
let parent = element.parent;
return parent
? mangleExportName(parent)
+ STATIC_DELIMITER
+ simpleName
: simpleName;
}
}
}
/** Adds the debug location of the specified expression at the specified range to the source map. */ /** Adds the debug location of the specified expression at the specified range to the source map. */
function addDebugLocation(expr: ExpressionRef, range: Range, module: Module, currentFunction: Function): void { function addDebugLocation(expr: ExpressionRef, range: Range, module: Module, currentFunction: Function): void {
var source = range.source; var source = range.source;

View File

@ -11,13 +11,15 @@ import {
Global, Global,
Enum, Enum,
EnumValue, EnumValue,
Field,
Function, Function,
Class,
Namespace,
FunctionPrototype, FunctionPrototype,
Class,
ClassPrototype, ClassPrototype,
Namespace,
ConstantValueKind, ConstantValueKind,
Interface Interface,
Property
} from "./program"; } from "./program";
import { import {
@ -41,52 +43,57 @@ abstract class ExportsWalker {
} }
walk(): void { walk(): void {
for (let element of this.program.moduleLevelExports.values()) { for (let element of this.program.moduleLevelExports.values()) this.visitElement(element);
this.visitElement(element);
}
} }
visitElement(element: Element): void { visitElement(element: Element): void {
switch (element.kind) { switch (element.kind) {
case ElementKind.GLOBAL: { case ElementKind.GLOBAL: {
if (element.is(CommonFlags.COMPILED)) { if (element.is(CommonFlags.COMPILED)) this.visitGlobal(<Global>element);
this.visitGlobal(<Global>element);
}
break; break;
} }
case ElementKind.ENUM: { case ElementKind.ENUM: {
if (element.is(CommonFlags.COMPILED)) { if (element.is(CommonFlags.COMPILED)) this.visitEnum(<Enum>element);
this.visitEnum(<Enum>element);
}
break; break;
} }
case ElementKind.FUNCTION_PROTOTYPE: { case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>element).instances.values()) { this.visitCompiledFunctions(<FunctionPrototype>element);
if (instance.is(CommonFlags.COMPILED)) {
this.visitFunction(<Function>instance);
}
}
break; break;
} }
case ElementKind.CLASS_PROTOTYPE: { case ElementKind.CLASS_PROTOTYPE: {
for (let instance of (<ClassPrototype>element).instances.values()) { this.visitCompiledClasses(<ClassPrototype>element);
if (instance.is(CommonFlags.COMPILED)) { break;
this.visitClass(<Class>instance);
} }
case ElementKind.FIELD: {
if ((<Field>element).is(CommonFlags.COMPILED)) this.visitField(<Field>element);
break;
} }
case ElementKind.PROPERTY: {
let prop = <Property>element;
let getter = prop.getterPrototype;
if (getter) this.visitCompiledFunctions(getter);
let setter = prop.setterPrototype;
if (setter) this.visitCompiledFunctions(setter);
break; break;
} }
case ElementKind.NAMESPACE: { case ElementKind.NAMESPACE: {
if ((<Namespace>element).is(CommonFlags.COMPILED)) { if (hasCompiledMember(<Namespace>element)) this.visitNamespace(<Namespace>element);
this.visitNamespace(<Namespace>element);
}
break; break;
} }
default: { default: assert(false);
assert(false);
break;
} }
} }
visitCompiledFunctions(element: FunctionPrototype): void {
for (let instance of element.instances.values()) {
if (instance.is(CommonFlags.COMPILED)) this.visitFunction(<Function>instance);
}
}
visitCompiledClasses(element: ClassPrototype): void {
for (let instance of element.instances.values()) {
if (instance.is(CommonFlags.COMPILED)) this.visitClass(<Class>instance);
}
} }
abstract visitGlobal(element: Global): void; abstract visitGlobal(element: Global): void;
@ -94,6 +101,7 @@ abstract class ExportsWalker {
abstract visitFunction(element: Function): void; abstract visitFunction(element: Function): void;
abstract visitClass(element: Class): void; abstract visitClass(element: Class): void;
abstract visitInterface(element: Interface): void; abstract visitInterface(element: Interface): void;
abstract visitField(element: Field): void;
abstract visitNamespace(element: Element): void; abstract visitNamespace(element: Element): void;
} }
@ -120,9 +128,7 @@ export class IDLBuilder extends ExportsWalker {
var sb = this.sb; var sb = this.sb;
var isConst = element.is(CommonFlags.INLINED); var isConst = element.is(CommonFlags.INLINED);
indent(sb, this.indentLevel); indent(sb, this.indentLevel);
if (isConst) { if (isConst) sb.push("const ");
sb.push("const ");
}
sb.push(this.typeToString(element.type)); sb.push(this.typeToString(element.type));
sb.push(" "); sb.push(" ");
sb.push(element.simpleName); sb.push(element.simpleName);
@ -158,11 +164,8 @@ export class IDLBuilder extends ExportsWalker {
if (member.kind == ElementKind.ENUMVALUE) { if (member.kind == ElementKind.ENUMVALUE) {
let isConst = (<EnumValue>member).is(CommonFlags.INLINED); let isConst = (<EnumValue>member).is(CommonFlags.INLINED);
indent(sb, this.indentLevel); indent(sb, this.indentLevel);
if (isConst) { if (isConst) sb.push("const ");
sb.push("const "); else sb.push("readonly ");
} else {
sb.push("readonly ");
}
sb.push("unsigned long "); sb.push("unsigned long ");
sb.push(name); sb.push(name);
if (isConst) { if (isConst) {
@ -173,9 +176,7 @@ export class IDLBuilder extends ExportsWalker {
} }
} }
for (let member of members.values()) { for (let member of members.values()) {
if (member.kind != ElementKind.ENUMVALUE) { if (member.kind != ElementKind.ENUMVALUE) this.visitElement(member);
this.visitElement(member);
}
} }
} }
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
@ -209,9 +210,7 @@ export class IDLBuilder extends ExportsWalker {
sb.push("interface "); sb.push("interface ");
sb.push(element.simpleName); sb.push(element.simpleName);
sb.push(" {\n"); sb.push(" {\n");
for (let member of members.values()) { for (let member of members.values()) this.visitElement(member);
this.visitElement(member);
}
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
sb.push("}\n"); sb.push("}\n");
} }
@ -234,6 +233,10 @@ export class IDLBuilder extends ExportsWalker {
this.visitClass(element); this.visitClass(element);
} }
visitField(element: Field): void {
// TODO
}
visitNamespace(element: Namespace): void { visitNamespace(element: Namespace): void {
if (this.seen.has(element)) return; if (this.seen.has(element)) return;
this.seen.add(element); this.seen.add(element);
@ -244,9 +247,7 @@ export class IDLBuilder extends ExportsWalker {
sb.push(" {\n"); sb.push(" {\n");
var members = element.members; var members = element.members;
if (members) { if (members) {
for (let member of members.values()) { for (let member of members.values()) this.visitElement(member);
this.visitElement(member);
}
} }
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
sb.push("}\n"); sb.push("}\n");
@ -311,8 +312,12 @@ export class TSDBuilder extends ExportsWalker {
var sb = this.sb; var sb = this.sb;
var isConst = element.is(CommonFlags.INLINED); var isConst = element.is(CommonFlags.INLINED);
indent(sb, this.indentLevel); indent(sb, this.indentLevel);
if (isConst) { if (element.is(CommonFlags.STATIC)) {
sb.push("const "); if (isConst) sb.push("static readonly ");
else assert(false);
} else {
if (isConst) sb.push("const ");
else sb.push("var ");
} }
sb.push(element.simpleName); sb.push(element.simpleName);
sb.push(": "); sb.push(": ");
@ -345,9 +350,7 @@ export class TSDBuilder extends ExportsWalker {
--numMembers; --numMembers;
} }
} }
if (numMembers) { if (numMembers) this.visitNamespace(element);
this.visitNamespace(element);
}
} }
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
sb.push("}\n"); sb.push("}\n");
@ -356,11 +359,22 @@ export class TSDBuilder extends ExportsWalker {
visitFunction(element: Function): void { visitFunction(element: Function): void {
if (this.seen.has(element)) return; if (this.seen.has(element)) return;
this.seen.add(element); this.seen.add(element);
if (element.is(CommonFlags.PRIVATE)) return;
var sb = this.sb; var sb = this.sb;
var signature = element.signature; var signature = element.signature;
indent(sb, this.indentLevel); indent(sb, this.indentLevel);
sb.push("function "); if (element.is(CommonFlags.PROTECTED)) sb.push("protected ");
if (element.is(CommonFlags.STATIC)) sb.push("static ");
if (element.is(CommonFlags.GET)) {
sb.push("get ");
sb.push(element.prototype.declaration.name.text); // 'get:funcName' internally
} else if (element.is(CommonFlags.SET)) {
sb.push("set ");
sb.push(element.prototype.declaration.name.text);
} else {
if (!element.is(CommonFlags.INSTANCE)) sb.push("function ");
sb.push(element.simpleName); sb.push(element.simpleName);
}
sb.push("("); sb.push("(");
var parameters = signature.parameterTypes; var parameters = signature.parameterTypes;
var numParameters = parameters.length; var numParameters = parameters.length;
@ -372,8 +386,12 @@ export class TSDBuilder extends ExportsWalker {
sb.push(": "); sb.push(": ");
sb.push(this.typeToString(parameters[i])); sb.push(this.typeToString(parameters[i]));
} }
if (element.isAny(CommonFlags.CONSTRUCTOR | CommonFlags.SET)) {
sb.push(")");
} else {
sb.push("): "); sb.push("): ");
sb.push(this.typeToString(signature.returnType)); sb.push(this.typeToString(signature.returnType));
}
sb.push(";\n"); sb.push(";\n");
this.visitNamespace(element); this.visitNamespace(element);
} }
@ -394,18 +412,22 @@ export class TSDBuilder extends ExportsWalker {
} }
sb.push(element.simpleName); sb.push(element.simpleName);
var base = element.base; var base = element.base;
if (base) { if (base && base.is(CommonFlags.COMPILED | CommonFlags.MODULE_EXPORT)) {
sb.push(" extends "); sb.push(" extends ");
sb.push(base.simpleName); // TODO: fqn sb.push(base.simpleName); // TODO: fqn
} }
sb.push(" {\n"); sb.push(" {\n");
var members = element.prototype.members; // static var members = element.prototype.members; // static
if (members) { if (members) {
// TODO for (let member of members.values()) {
this.visitElement(member);
} }
}
var ctor = element.constructorInstance;
if (ctor) this.visitFunction(ctor);
members = element.members; // instance members = element.members; // instance
if (members) { if (members) {
// TODO for (let member of members.values()) this.visitElement(member);
} }
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
sb.push("}\n"); sb.push("}\n");
@ -415,6 +437,40 @@ export class TSDBuilder extends ExportsWalker {
this.visitClass(element); this.visitClass(element);
} }
visitField(element: Field): void {
if (element.is(CommonFlags.PRIVATE)) return;
var sb = this.sb;
indent(sb, this.indentLevel);
if (element.is(CommonFlags.PROTECTED)) sb.push("protected ");
if (element.is(CommonFlags.STATIC)) sb.push("static ");
if (element.is(CommonFlags.READONLY)) sb.push("readonly ");
sb.push(element.simpleName);
sb.push(": ");
sb.push(this.typeToString(element.type));
sb.push(";\n");
/* TBD: the compiler implicitly generates setters if the class is exported
indent(sb, this.indentLevel);
sb.push("get ");
sb.push(element.simpleName);
sb.push("(): ");
sb.push(this.typeToString(element.type));
sb.push(";\n");
if (!element.is(CommonFlags.READONLY)) {
indent(sb, this.indentLevel);
if (element.is(CommonFlags.PROTECTED)) sb.push("protected ");
if (element.is(CommonFlags.STATIC)) sb.push("static ");
if (element.is(CommonFlags.READONLY)) sb.push("readonly ");
sb.push("set ");
sb.push(element.simpleName);
sb.push("(");
sb.push(element.simpleName);
sb.push(": ");
sb.push(this.typeToString(element.type));
sb.push(");\n");
}
*/
}
visitNamespace(element: Element): void { visitNamespace(element: Element): void {
var members = element.members; var members = element.members;
if (members && members.size) { if (members && members.size) {
@ -423,9 +479,7 @@ export class TSDBuilder extends ExportsWalker {
sb.push("namespace "); sb.push("namespace ");
sb.push(element.simpleName); sb.push(element.simpleName);
sb.push(" {\n"); sb.push(" {\n");
for (let member of members.values()) { for (let member of members.values()) this.visitElement(member);
this.visitElement(member);
}
indent(sb, --this.indentLevel); indent(sb, --this.indentLevel);
sb.push("}\n"); sb.push("}\n");
} }
@ -477,3 +531,33 @@ export class TSDBuilder extends ExportsWalker {
} }
// TODO: C bindings? or is this sufficiently covered by WebIDL and using a 3rd-party tool? // TODO: C bindings? or is this sufficiently covered by WebIDL and using a 3rd-party tool?
// helpers
/** Tests if a namespace-like element has at least one compiled member. */
function hasCompiledMember(element: Element): bool {
var members = element.members;
if (members) {
for (let member of members.values()) {
switch (member.kind) {
case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>member).instances.values()) {
if (instance.is(CommonFlags.COMPILED)) return true;
}
break;
}
case ElementKind.CLASS_PROTOTYPE: {
for (let instance of (<ClassPrototype>member).instances.values()) {
if (instance.is(CommonFlags.COMPILED)) return true;
}
break;
}
default: {
if (member.is(CommonFlags.COMPILED) || hasCompiledMember(member)) return true;
break;
}
}
}
}
return false;
}

View File

@ -28,9 +28,8 @@ import {
CommonTypeNode, CommonTypeNode,
TypeNode, TypeNode,
TypeParameterNode, TypeParameterNode,
// ParameterNode, ParameterKind,
// ParameterKind, SignatureNode,
// SignatureNode,
DecoratorNode, DecoratorNode,
DecoratorKind, DecoratorKind,
@ -59,12 +58,10 @@ import {
MethodDeclaration, MethodDeclaration,
NamespaceDeclaration, NamespaceDeclaration,
TypeDeclaration, TypeDeclaration,
VariableDeclaration,
VariableLikeDeclarationStatement, VariableLikeDeclarationStatement,
VariableStatement, VariableStatement,
ParameterKind,
SignatureNode,
VariableDeclaration,
stringToDecoratorKind stringToDecoratorKind
} from "./ast"; } from "./ast";
@ -533,7 +530,7 @@ export class Program extends DiagnosticEmitter {
) )
: DecoratorFlags.NONE : DecoratorFlags.NONE
); );
prototype.namespace = namespace; prototype.parent = namespace;
this.elementsLookup.set(internalName, prototype); this.elementsLookup.set(internalName, prototype);
var implementsTypes = declaration.implementsTypes; var implementsTypes = declaration.implementsTypes;
@ -573,11 +570,9 @@ export class Program extends DiagnosticEmitter {
namespace.members = new Map(); namespace.members = new Map();
} }
namespace.members.set(simpleName, prototype); namespace.members.set(simpleName, prototype);
if (namespace.is(CommonFlags.MODULE_EXPORT)) { if (namespace.is(CommonFlags.MODULE_EXPORT) && prototype.is(CommonFlags.EXPORT)) {
if (prototype.is(CommonFlags.EXPORT)) {
prototype.set(CommonFlags.MODULE_EXPORT); prototype.set(CommonFlags.MODULE_EXPORT);
} }
}
// otherwise add to file-level exports if exported // otherwise add to file-level exports if exported
} else if (prototype.is(CommonFlags.EXPORT)) { } else if (prototype.is(CommonFlags.EXPORT)) {
@ -662,8 +657,12 @@ export class Program extends DiagnosticEmitter {
Type.void, // resolved later on Type.void, // resolved later on
declaration declaration
); );
staticField.parent = classPrototype;
classPrototype.members.set(name, staticField); classPrototype.members.set(name, staticField);
this.elementsLookup.set(internalName, staticField); this.elementsLookup.set(internalName, staticField);
if (classPrototype.is(CommonFlags.MODULE_EXPORT)) {
staticField.set(CommonFlags.MODULE_EXPORT);
}
// instance fields are remembered until resolved // instance fields are remembered until resolved
} else { } else {
@ -685,6 +684,7 @@ export class Program extends DiagnosticEmitter {
declaration declaration
); );
classPrototype.instanceMembers.set(name, instanceField); classPrototype.instanceMembers.set(name, instanceField);
// TBD: no need to mark as MODULE_EXPORT
} }
} }
@ -958,6 +958,7 @@ export class Program extends DiagnosticEmitter {
this.elementsLookup.set(internalPropertyName, propertyElement); this.elementsLookup.set(internalPropertyName, propertyElement);
if (classPrototype.is(CommonFlags.MODULE_EXPORT)) { if (classPrototype.is(CommonFlags.MODULE_EXPORT)) {
propertyElement.set(CommonFlags.MODULE_EXPORT); propertyElement.set(CommonFlags.MODULE_EXPORT);
instancePrototype.set(CommonFlags.MODULE_EXPORT);
} }
} }
} }
@ -976,7 +977,7 @@ export class Program extends DiagnosticEmitter {
} }
var simpleName = declaration.name.text; var simpleName = declaration.name.text;
var element = new Enum(this, simpleName, internalName, declaration); var element = new Enum(this, simpleName, internalName, declaration);
element.namespace = namespace; element.parent = namespace;
this.elementsLookup.set(internalName, element); this.elementsLookup.set(internalName, element);
if (namespace) { if (namespace) {
@ -992,7 +993,7 @@ export class Program extends DiagnosticEmitter {
namespace.members = new Map(); namespace.members = new Map();
} }
namespace.members.set(simpleName, element); namespace.members.set(simpleName, element);
if (namespace.is(CommonFlags.MODULE_EXPORT)) { if (namespace.is(CommonFlags.MODULE_EXPORT) && element.is(CommonFlags.EXPORT)) {
element.set(CommonFlags.MODULE_EXPORT); element.set(CommonFlags.MODULE_EXPORT);
} }
} else if (element.is(CommonFlags.EXPORT)) { // no namespace } else if (element.is(CommonFlags.EXPORT)) { // no namespace
@ -1031,7 +1032,6 @@ export class Program extends DiagnosticEmitter {
): void { ): void {
var name = declaration.name.text; var name = declaration.name.text;
var internalName = declaration.fileLevelInternalName; var internalName = declaration.fileLevelInternalName;
var isModuleExport = enm.is(CommonFlags.MODULE_EXPORT);
if (enm.members) { if (enm.members) {
if (enm.members.has(name)) { if (enm.members.has(name)) {
this.error( this.error(
@ -1045,7 +1045,7 @@ export class Program extends DiagnosticEmitter {
} }
var value = new EnumValue(enm, this, name, internalName, declaration); var value = new EnumValue(enm, this, name, internalName, declaration);
enm.members.set(name, value); enm.members.set(name, value);
if (isModuleExport) { if (enm.is(CommonFlags.MODULE_EXPORT)) {
value.set(CommonFlags.MODULE_EXPORT); value.set(CommonFlags.MODULE_EXPORT);
} }
} }
@ -1212,7 +1212,7 @@ export class Program extends DiagnosticEmitter {
) )
: DecoratorFlags.NONE : DecoratorFlags.NONE
); );
prototype.namespace = namespace; prototype.parent = namespace;
this.elementsLookup.set(internalName, prototype); this.elementsLookup.set(internalName, prototype);
if (namespace) { if (namespace) {
@ -1229,6 +1229,7 @@ export class Program extends DiagnosticEmitter {
} }
namespace.members.set(simpleName, prototype); namespace.members.set(simpleName, prototype);
if (namespace.is(CommonFlags.MODULE_EXPORT) && prototype.is(CommonFlags.EXPORT)) { if (namespace.is(CommonFlags.MODULE_EXPORT) && prototype.is(CommonFlags.EXPORT)) {
prototype.parent = namespace;
prototype.set(CommonFlags.MODULE_EXPORT); prototype.set(CommonFlags.MODULE_EXPORT);
} }
} else if (prototype.is(CommonFlags.EXPORT)) { // no namespace } else if (prototype.is(CommonFlags.EXPORT)) { // no namespace
@ -1358,7 +1359,7 @@ export class Program extends DiagnosticEmitter {
? this.filterDecorators(decorators, DecoratorFlags.GLOBAL) ? this.filterDecorators(decorators, DecoratorFlags.GLOBAL)
: DecoratorFlags.NONE : DecoratorFlags.NONE
); );
prototype.namespace = namespace; prototype.parent = namespace;
this.elementsLookup.set(internalName, prototype); this.elementsLookup.set(internalName, prototype);
if (namespace) { if (namespace) {
@ -1436,7 +1437,7 @@ export class Program extends DiagnosticEmitter {
var namespace = this.elementsLookup.get(internalName); var namespace = this.elementsLookup.get(internalName);
if (!namespace) { if (!namespace) {
namespace = new Namespace(this, simpleName, internalName, declaration); namespace = new Namespace(this, simpleName, internalName, declaration);
namespace.namespace = parentNamespace; namespace.parent = parentNamespace;
this.elementsLookup.set(internalName, namespace); this.elementsLookup.set(internalName, namespace);
this.checkGlobalOptions(namespace, declaration); this.checkGlobalOptions(namespace, declaration);
} }
@ -1563,7 +1564,7 @@ export class Program extends DiagnosticEmitter {
Type.void, // resolved later on Type.void, // resolved later on
declaration declaration
); );
global.namespace = namespace; global.parent = namespace;
this.elementsLookup.set(internalName, global); this.elementsLookup.set(internalName, global);
if (namespace) { if (namespace) {
@ -1836,14 +1837,14 @@ export class Program extends DiagnosticEmitter {
// } // }
// search contextual parent namespaces if applicable // search contextual parent namespaces if applicable
if (namespace = contextualFunction.prototype.namespace) { if (namespace = contextualFunction.prototype.parent) {
do { do {
if (element = this.elementsLookup.get(namespace.internalName + STATIC_DELIMITER + name)) { if (element = this.elementsLookup.get(namespace.internalName + STATIC_DELIMITER + name)) {
this.resolvedThisExpression = null; this.resolvedThisExpression = null;
this.resolvedElementExpression = null; this.resolvedElementExpression = null;
return element; // LOCAL return element; // LOCAL
} }
} while (namespace = namespace.namespace); } while (namespace = namespace.parent);
} }
} }
@ -2061,7 +2062,7 @@ export class Program extends DiagnosticEmitter {
return explicitLocal; return explicitLocal;
} }
} }
let parent = contextualFunction.memberOf; let parent = contextualFunction.parent;
if (parent) { if (parent) {
this.resolvedThisExpression = null; this.resolvedThisExpression = null;
this.resolvedElementExpression = null; this.resolvedElementExpression = null;
@ -2082,7 +2083,7 @@ export class Program extends DiagnosticEmitter {
return explicitLocal; return explicitLocal;
} }
} }
let parent = contextualFunction.memberOf; let parent = contextualFunction.parent;
if (parent && parent.kind == ElementKind.CLASS && (parent = (<Class>parent).base)) { if (parent && parent.kind == ElementKind.CLASS && (parent = (<Class>parent).base)) {
this.resolvedThisExpression = null; this.resolvedThisExpression = null;
this.resolvedElementExpression = null; this.resolvedElementExpression = null;
@ -2308,8 +2309,8 @@ export abstract class Element {
decoratorFlags: DecoratorFlags = DecoratorFlags.NONE; decoratorFlags: DecoratorFlags = DecoratorFlags.NONE;
/** Namespaced member elements. */ /** Namespaced member elements. */
members: Map<string,Element> | null = null; members: Map<string,Element> | null = null;
/** Parent namespace, if applicable. */ /** Parent element, if applicable. */
namespace: Element | null = null; parent: Element | null = null;
/** Constructs a new element, linking it to its containing {@link Program}. */ /** Constructs a new element, linking it to its containing {@link Program}. */
protected constructor(program: Program, simpleName: string, internalName: string) { protected constructor(program: Program, simpleName: string, internalName: string) {
@ -2378,8 +2379,6 @@ export class EnumValue extends Element {
/** Declaration reference. */ /** Declaration reference. */
declaration: EnumValueDeclaration; declaration: EnumValueDeclaration;
/** Parent enum. */
enum: Enum;
/** Constant value, if applicable. */ /** Constant value, if applicable. */
constantValue: i32 = 0; constantValue: i32 = 0;
@ -2391,7 +2390,7 @@ export class EnumValue extends Element {
declaration: EnumValueDeclaration declaration: EnumValueDeclaration
) { ) {
super(program, simpleName, internalName); super(program, simpleName, internalName);
this.enum = enm; this.parent = enm;
this.declaration = declaration; this.declaration = declaration;
} }
} }
@ -2732,8 +2731,6 @@ export class Function extends Element {
prototype: FunctionPrototype; prototype: FunctionPrototype;
/** Function signature. */ /** Function signature. */
signature: Signature; signature: Signature;
/** If a member of another namespace-like element, the concrete element it is a member of. */
memberOf: Element | null;
/** Map of locals by name. */ /** Map of locals by name. */
locals: Map<string,Local> = new Map(); locals: Map<string,Local> = new Map();
/** List of additional non-parameter locals. */ /** List of additional non-parameter locals. */
@ -2764,19 +2761,19 @@ export class Function extends Element {
prototype: FunctionPrototype, prototype: FunctionPrototype,
internalName: string, internalName: string,
signature: Signature, signature: Signature,
memberOf: Element | null = null, parent: Element | null = null,
contextualTypeArguments: Map<string,Type> | null = null contextualTypeArguments: Map<string,Type> | null = null
) { ) {
super(prototype.program, prototype.simpleName, internalName); super(prototype.program, prototype.simpleName, internalName);
this.prototype = prototype; this.prototype = prototype;
this.signature = signature; this.signature = signature;
this.memberOf = memberOf; this.parent = parent;
this.flags = prototype.flags; this.flags = prototype.flags;
this.decoratorFlags = prototype.decoratorFlags; this.decoratorFlags = prototype.decoratorFlags;
this.contextualTypeArguments = contextualTypeArguments; this.contextualTypeArguments = contextualTypeArguments;
if (!(prototype.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN) || prototype.is(CommonFlags.DECLARE))) { if (!(prototype.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN) || prototype.is(CommonFlags.DECLARE))) {
let localIndex = 0; let localIndex = 0;
if (memberOf && memberOf.kind == ElementKind.CLASS) { if (parent && parent.kind == ElementKind.CLASS) {
assert(this.is(CommonFlags.INSTANCE)); assert(this.is(CommonFlags.INSTANCE));
this.locals.set( this.locals.set(
"this", "this",
@ -2787,7 +2784,7 @@ export class Function extends Element {
assert(signature.thisType) assert(signature.thisType)
) )
); );
let inheritedTypeArguments = (<Class>memberOf).contextualTypeArguments; let inheritedTypeArguments = (<Class>parent).contextualTypeArguments;
if (inheritedTypeArguments) { if (inheritedTypeArguments) {
if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map(); if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map();
for (let [inheritedName, inheritedType] of inheritedTypeArguments) { for (let [inheritedName, inheritedType] of inheritedTypeArguments) {
@ -3048,12 +3045,14 @@ export class Field extends VariableLikeElement {
prototype: FieldPrototype, prototype: FieldPrototype,
internalName: string, internalName: string,
type: Type, type: Type,
declaration: FieldDeclaration declaration: FieldDeclaration,
parent: Class
) { ) {
super(prototype.program, prototype.simpleName, internalName, type, declaration); super(prototype.program, prototype.simpleName, internalName, type, declaration);
this.prototype = prototype; this.prototype = prototype;
this.flags = prototype.flags; this.flags = prototype.flags;
this.type = type; this.type = type;
this.parent = parent;
} }
} }
@ -3219,7 +3218,8 @@ export class ClassPrototype extends Element {
<FieldPrototype>member, <FieldPrototype>member,
internalName + INSTANCE_DELIMITER + (<FieldPrototype>member).simpleName, internalName + INSTANCE_DELIMITER + (<FieldPrototype>member).simpleName,
fieldType, fieldType,
fieldDeclaration fieldDeclaration,
instance
); );
switch (fieldType.byteSize) { // align switch (fieldType.byteSize) { // align
case 1: break; case 1: break;

View File

@ -557,21 +557,24 @@ export class Signature {
return thisReturnType == targetReturnType || thisReturnType.isAssignableTo(targetReturnType); return thisReturnType == targetReturnType || thisReturnType.isAssignableTo(targetReturnType);
} }
/** Converts this signature to a function type string. */ /** Converts a signature to a function type string. */
toSignatureString(): string { static makeSignatureString(parameterTypes: Type[] | null, returnType: Type, thisType: Type | null = null): string {
var sb = []; var sb = [];
var thisType = this.thisType; if (thisType) sb.push(thisType.toSignatureString());
if (thisType) { if (parameterTypes) {
sb.push(thisType.toSignatureString());
}
var parameterTypes = this.parameterTypes;
for (let i = 0, k = parameterTypes.length; i < k; ++i) { for (let i = 0, k = parameterTypes.length; i < k; ++i) {
sb.push(parameterTypes[i].toSignatureString()); sb.push(parameterTypes[i].toSignatureString());
} }
sb.push(this.returnType.toSignatureString()); }
sb.push(returnType.toSignatureString());
return sb.join(""); return sb.join("");
} }
/** Converts this signature to a function type string. */
toSignatureString(): string {
return Signature.makeSignatureString(this.parameterTypes, this.returnType, this.thisType);
}
/** Converts this signature to a string. */ /** Converts this signature to a string. */
toString(includeThis: bool = false): string { toString(includeThis: bool = false): string {
var sb = new Array<string>(); var sb = new Array<string>();

View File

@ -18,20 +18,20 @@
(global $enum/SelfReference.ZERO i32 (i32.const 0)) (global $enum/SelfReference.ZERO i32 (i32.const 0))
(global $enum/SelfReference.ONE i32 (i32.const 1)) (global $enum/SelfReference.ONE i32 (i32.const 1))
(memory $0 1) (memory $0 1)
(export "enum/Implicit.ZERO" (global $enum/Implicit.ZERO)) (export "Implicit.ZERO" (global $enum/Implicit.ZERO))
(export "enum/Implicit.ONE" (global $enum/Implicit.ONE)) (export "Implicit.ONE" (global $enum/Implicit.ONE))
(export "enum/Implicit.TWO" (global $enum/Implicit.TWO)) (export "Implicit.TWO" (global $enum/Implicit.TWO))
(export "enum/Implicit.THREE" (global $enum/Implicit.THREE)) (export "Implicit.THREE" (global $enum/Implicit.THREE))
(export "enum/Explicit.ZERO" (global $enum/Explicit.ZERO)) (export "Explicit.ZERO" (global $enum/Explicit.ZERO))
(export "enum/Explicit.ONE" (global $enum/Explicit.ONE)) (export "Explicit.ONE" (global $enum/Explicit.ONE))
(export "enum/Explicit.TWO" (global $enum/Explicit.TWO)) (export "Explicit.TWO" (global $enum/Explicit.TWO))
(export "enum/Explicit.THREE" (global $enum/Explicit.THREE)) (export "Explicit.THREE" (global $enum/Explicit.THREE))
(export "enum/Mixed.ZERO" (global $enum/Mixed.ZERO)) (export "Mixed.ZERO" (global $enum/Mixed.ZERO))
(export "enum/Mixed.ONE" (global $enum/Mixed.ONE)) (export "Mixed.ONE" (global $enum/Mixed.ONE))
(export "enum/Mixed.THREE" (global $enum/Mixed.THREE)) (export "Mixed.THREE" (global $enum/Mixed.THREE))
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR)) (export "Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "enum/SelfReference.ZERO" (global $enum/SelfReference.ZERO)) (export "SelfReference.ZERO" (global $enum/SelfReference.ZERO))
(export "enum/SelfReference.ONE" (global $enum/SelfReference.ONE)) (export "SelfReference.ONE" (global $enum/SelfReference.ONE))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32) (func $enum/getZero (; 0 ;) (type $i) (result i32)

View File

@ -19,20 +19,20 @@
(global $enum/SelfReference.ONE i32 (i32.const 1)) (global $enum/SelfReference.ONE i32 (i32.const 1))
(global $HEAP_BASE i32 (i32.const 4)) (global $HEAP_BASE i32 (i32.const 4))
(memory $0 1) (memory $0 1)
(export "enum/Implicit.ZERO" (global $enum/Implicit.ZERO)) (export "Implicit.ZERO" (global $enum/Implicit.ZERO))
(export "enum/Implicit.ONE" (global $enum/Implicit.ONE)) (export "Implicit.ONE" (global $enum/Implicit.ONE))
(export "enum/Implicit.TWO" (global $enum/Implicit.TWO)) (export "Implicit.TWO" (global $enum/Implicit.TWO))
(export "enum/Implicit.THREE" (global $enum/Implicit.THREE)) (export "Implicit.THREE" (global $enum/Implicit.THREE))
(export "enum/Explicit.ZERO" (global $enum/Explicit.ZERO)) (export "Explicit.ZERO" (global $enum/Explicit.ZERO))
(export "enum/Explicit.ONE" (global $enum/Explicit.ONE)) (export "Explicit.ONE" (global $enum/Explicit.ONE))
(export "enum/Explicit.TWO" (global $enum/Explicit.TWO)) (export "Explicit.TWO" (global $enum/Explicit.TWO))
(export "enum/Explicit.THREE" (global $enum/Explicit.THREE)) (export "Explicit.THREE" (global $enum/Explicit.THREE))
(export "enum/Mixed.ZERO" (global $enum/Mixed.ZERO)) (export "Mixed.ZERO" (global $enum/Mixed.ZERO))
(export "enum/Mixed.ONE" (global $enum/Mixed.ONE)) (export "Mixed.ONE" (global $enum/Mixed.ONE))
(export "enum/Mixed.THREE" (global $enum/Mixed.THREE)) (export "Mixed.THREE" (global $enum/Mixed.THREE))
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR)) (export "Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "enum/SelfReference.ZERO" (global $enum/SelfReference.ZERO)) (export "SelfReference.ZERO" (global $enum/SelfReference.ZERO))
(export "enum/SelfReference.ONE" (global $enum/SelfReference.ONE)) (export "SelfReference.ONE" (global $enum/SelfReference.ONE))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32) (func $enum/getZero (; 0 ;) (type $i) (result i32)

View File

@ -11,7 +11,7 @@
(export "a" (global $export/a)) (export "a" (global $export/a))
(export "b" (global $export/b)) (export "b" (global $export/b))
(export "renamed_c" (global $export/c)) (export "renamed_c" (global $export/c))
(export "two" (func $export/ns.two)) (export "ns.two" (func $export/ns.two))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.add (i32.add

View File

@ -12,7 +12,7 @@
(export "a" (global $export/a)) (export "a" (global $export/a))
(export "b" (global $export/b)) (export "b" (global $export/b))
(export "renamed_c" (global $export/c)) (export "renamed_c" (global $export/c))
(export "two" (func $export/ns.two)) (export "ns.two" (func $export/ns.two))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return (return

View File

@ -0,0 +1,66 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $i (func (result i32)))
(type $ii (func (param i32) (result i32)))
(type $iiv (func (param i32 i32)))
(type $iv (func (param i32)))
(global $exports/Animal.CAT i32 (i32.const 0))
(global $exports/Animal.DOG i32 (i32.const 1))
(global $exports/animals.Animal.CAT i32 (i32.const 0))
(global $exports/animals.Animal.DOG i32 (i32.const 1))
(global $exports/Car.TIRES i32 (i32.const 4))
(global $exports/vehicles.Car.TIRES i32 (i32.const 4))
(global $exports/outer.inner.a i32 (i32.const 42))
(memory $0 1)
(export "add" (func $exports/add))
(export "math.sub" (func $exports/math.sub))
(export "Animal.CAT" (global $exports/Animal.CAT))
(export "Animal.DOG" (global $exports/Animal.DOG))
(export "animals.Animal.CAT" (global $exports/animals.Animal.CAT))
(export "animals.Animal.DOG" (global $exports/animals.Animal.DOG))
(export "Car.TIRES" (global $exports/Car.TIRES))
(export "Car.getNumTires" (func $exports/Car.getNumTires))
(export "Car#get:doors" (func $Car#get:doors))
(export "Car#set:doors" (func $Car#set:doors))
(export "Car#get:numDoors" (func $Car#get:doors))
(export "Car#set:numDoors" (func $Car#set:doors))
(export "Car#openDoors" (func $exports/Car#openDoors))
(export "vehicles.Car.TIRES" (global $exports/vehicles.Car.TIRES))
(export "vehicles.Car.getNumTires" (func $exports/Car.getNumTires))
(export "vehicles.Car#get:doors" (func $Car#get:doors))
(export "vehicles.Car#set:doors" (func $Car#set:doors))
(export "vehicles.Car#get:numDoors" (func $Car#get:doors))
(export "vehicles.Car#set:numDoors" (func $Car#set:doors))
(export "vehicles.Car#openDoors" (func $exports/Car#openDoors))
(export "outer.inner.a" (global $exports/outer.inner.a))
(export "memory" (memory $0))
(func $exports/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(get_local $0)
(get_local $1)
)
)
(func $exports/math.sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.sub
(get_local $0)
(get_local $1)
)
)
(func $exports/Car.getNumTires (; 2 ;) (type $i) (result i32)
(i32.const 4)
)
(func $Car#get:doors (; 3 ;) (type $ii) (param $0 i32) (result i32)
(i32.load
(get_local $0)
)
)
(func $Car#set:doors (; 4 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(get_local $0)
(get_local $1)
)
)
(func $exports/Car#openDoors (; 5 ;) (type $iv) (param $0 i32)
(nop)
)
)

54
tests/compiler/exports.ts Normal file
View File

@ -0,0 +1,54 @@
// top-level function
export function add(a: i32, b: i32): i32 {
return a + b;
}
// namespaced function
export namespace math {
export function sub(a: i32, b: i32): i32 {
return a - b;
}
}
// top-level enum
export enum Animal {
CAT,
DOG
}
// namespaced enum
export namespace animals {
export enum Animal {
CAT,
DOG
}
}
// top-level class
export class Car {
static readonly TIRES: i32 = 4;
static getNumTires(): i32 { return this.TIRES; }
constructor(public doors: i32 = 2) { this.doors = doors; }
get numDoors(): i32 { return this.doors; }
set numDoors(doors: i32) { this.doors = doors; }
openDoors(): void {}
}
// namespaced class
export namespace vehicles {
export class Car {
static readonly TIRES: i32 = 4;
static getNumTires(): i32 { return this.TIRES; }
constructor(public doors: i32 = 2) { this.doors = doors; }
get numDoors(): i32 { return this.doors; }
set numDoors(doors: i32) { this.doors = doors; }
openDoors(): void {}
}
}
// namespaced namespace
export namespace outer {
export namespace inner {
export const a = 42;
}
}

View File

@ -0,0 +1,116 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $i (func (result i32)))
(type $ii (func (param i32) (result i32)))
(type $iiv (func (param i32 i32)))
(type $iv (func (param i32)))
(global $exports/Animal.CAT i32 (i32.const 0))
(global $exports/Animal.DOG i32 (i32.const 1))
(global $exports/animals.Animal.CAT i32 (i32.const 0))
(global $exports/animals.Animal.DOG i32 (i32.const 1))
(global $exports/Car.TIRES i32 (i32.const 4))
(global $exports/vehicles.Car.TIRES i32 (i32.const 4))
(global $exports/outer.inner.a i32 (i32.const 42))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "add" (func $exports/add))
(export "math.sub" (func $exports/math.sub))
(export "Animal.CAT" (global $exports/Animal.CAT))
(export "Animal.DOG" (global $exports/Animal.DOG))
(export "animals.Animal.CAT" (global $exports/animals.Animal.CAT))
(export "animals.Animal.DOG" (global $exports/animals.Animal.DOG))
(export "Car.TIRES" (global $exports/Car.TIRES))
(export "Car.getNumTires" (func $exports/Car.getNumTires))
(export "Car#get:doors" (func $Car#get:doors))
(export "Car#set:doors" (func $Car#set:doors))
(export "Car#get:numDoors" (func $exports/Car#get:numDoors))
(export "Car#set:numDoors" (func $exports/Car#set:numDoors))
(export "Car#openDoors" (func $exports/Car#openDoors))
(export "vehicles.Car.TIRES" (global $exports/vehicles.Car.TIRES))
(export "vehicles.Car.getNumTires" (func $exports/vehicles.Car.getNumTires))
(export "vehicles.Car#get:doors" (func $vehicles.Car#get:doors))
(export "vehicles.Car#set:doors" (func $vehicles.Car#set:doors))
(export "vehicles.Car#get:numDoors" (func $exports/vehicles.Car#get:numDoors))
(export "vehicles.Car#set:numDoors" (func $exports/vehicles.Car#set:numDoors))
(export "vehicles.Car#openDoors" (func $exports/vehicles.Car#openDoors))
(export "outer.inner.a" (global $exports/outer.inner.a))
(export "memory" (memory $0))
(func $exports/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(i32.add
(get_local $0)
(get_local $1)
)
)
)
(func $exports/math.sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(i32.sub
(get_local $0)
(get_local $1)
)
)
)
(func $exports/Car.getNumTires (; 2 ;) (type $i) (result i32)
(return
(i32.const 4)
)
)
(func $Car#get:doors (; 3 ;) (type $ii) (param $0 i32) (result i32)
(i32.load
(get_local $0)
)
)
(func $Car#set:doors (; 4 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(get_local $0)
(get_local $1)
)
)
(func $exports/Car#get:numDoors (; 5 ;) (type $ii) (param $0 i32) (result i32)
(return
(i32.load
(get_local $0)
)
)
)
(func $exports/Car#set:numDoors (; 6 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(get_local $0)
(get_local $1)
)
)
(func $exports/Car#openDoors (; 7 ;) (type $iv) (param $0 i32)
)
(func $exports/vehicles.Car.getNumTires (; 8 ;) (type $i) (result i32)
(return
(i32.const 4)
)
)
(func $vehicles.Car#get:doors (; 9 ;) (type $ii) (param $0 i32) (result i32)
(i32.load
(get_local $0)
)
)
(func $vehicles.Car#set:doors (; 10 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(get_local $0)
(get_local $1)
)
)
(func $exports/vehicles.Car#get:numDoors (; 11 ;) (type $ii) (param $0 i32) (result i32)
(return
(i32.load
(get_local $0)
)
)
)
(func $exports/vehicles.Car#set:numDoors (; 12 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(get_local $0)
(get_local $1)
)
)
(func $exports/vehicles.Car#openDoors (; 13 ;) (type $iv) (param $0 i32)
)
)

View File

@ -54,10 +54,10 @@
(export "anExportedConstantGlobal" (global $showcase/anExportedConstantGlobal)) (export "anExportedConstantGlobal" (global $showcase/anExportedConstantGlobal))
(export "aConstantGlobal" (global $showcase/aConstantGlobal)) (export "aConstantGlobal" (global $showcase/aConstantGlobal))
(export "anAliasedConstantGlobal" (global $showcase/anExportedConstantGlobal)) (export "anAliasedConstantGlobal" (global $showcase/anExportedConstantGlobal))
(export "showcase/AnEnum.ONE" (global $showcase/AnEnum.ONE)) (export "AnEnum.ONE" (global $showcase/AnEnum.ONE))
(export "showcase/AnEnum.TWO" (global $showcase/AnEnum.TWO)) (export "AnEnum.TWO" (global $showcase/AnEnum.TWO))
(export "showcase/AnEnum.FOUR" (global $showcase/AnEnum.FOUR)) (export "AnEnum.FOUR" (global $showcase/AnEnum.FOUR))
(export "showcase/AnEnum.FIVE" (global $showcase/AnEnum.FIVE)) (export "AnEnum.FIVE" (global $showcase/AnEnum.FIVE))
(export "anExportedFunction" (func $showcase/anExportedFunction)) (export "anExportedFunction" (func $showcase/anExportedFunction))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)

View File

@ -64,10 +64,10 @@
(export "anExportedConstantGlobal" (global $showcase/anExportedConstantGlobal)) (export "anExportedConstantGlobal" (global $showcase/anExportedConstantGlobal))
(export "aConstantGlobal" (global $showcase/aConstantGlobal)) (export "aConstantGlobal" (global $showcase/aConstantGlobal))
(export "anAliasedConstantGlobal" (global $showcase/anExportedConstantGlobal)) (export "anAliasedConstantGlobal" (global $showcase/anExportedConstantGlobal))
(export "showcase/AnEnum.ONE" (global $showcase/AnEnum.ONE)) (export "AnEnum.ONE" (global $showcase/AnEnum.ONE))
(export "showcase/AnEnum.TWO" (global $showcase/AnEnum.TWO)) (export "AnEnum.TWO" (global $showcase/AnEnum.TWO))
(export "showcase/AnEnum.FOUR" (global $showcase/AnEnum.FOUR)) (export "AnEnum.FOUR" (global $showcase/AnEnum.FOUR))
(export "showcase/AnEnum.FIVE" (global $showcase/AnEnum.FIVE)) (export "AnEnum.FIVE" (global $showcase/AnEnum.FIVE))
(export "anExportedFunction" (func $showcase/anExportedFunction)) (export "anExportedFunction" (func $showcase/anExportedFunction))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)