Search parent namespaces when resolving identifiers

This commit is contained in:
dcodeIO 2017-12-27 19:17:29 +01:00
parent ba61a5e414
commit eccac129ad
9 changed files with 264 additions and 253 deletions

View File

@ -183,8 +183,7 @@ export class Compiler extends DiagnosticEmitter {
/** Compiles a {@link Program} to a {@link Module} using the specified options. */ /** Compiles a {@link Program} to a {@link Module} using the specified options. */
static compile(program: Program, options: Options | null = null): Module { static compile(program: Program, options: Options | null = null): Module {
const compiler: Compiler = new Compiler(program, options); return new Compiler(program, options).compile();
return compiler.compile();
} }
/** Constructs a new compiler for a {@link Program} using the specified options. */ /** Constructs a new compiler for a {@link Program} using the specified options. */
@ -203,23 +202,20 @@ export class Compiler extends DiagnosticEmitter {
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */ /** Performs compilation of the underlying {@link Program} to a {@link Module}. */
compile(): Module { compile(): Module {
const program: Program = this.program;
// initialize lookup maps, built-ins, imports, exports, etc. // initialize lookup maps, built-ins, imports, exports, etc.
program.initialize(this.options.target); this.program.initialize(this.options.target);
// compile entry file (exactly one, usually) // compile entry file (exactly one, usually)
const sources: Source[] = program.sources; const sources: Source[] = this.program.sources;
let i: i32, k: i32 = sources.length; let i: i32, k = sources.length;
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i)
const source: Source = sources[i]; if (sources[i].isEntry)
if (source.isEntry) this.compileSource(sources[i]);
this.compileSource(source);
}
// make start function if not empty // make start function if not empty
if (this.startFunctionBody.length) { if (this.startFunctionBody.length) {
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(NativeType.None, []); let typeRef = this.module.getFunctionTypeBySignature(NativeType.None, []);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType("v", NativeType.None, []); typeRef = this.module.addFunctionType("v", NativeType.None, []);
this.module.setStart( this.module.setStart(
@ -231,21 +227,21 @@ export class Compiler extends DiagnosticEmitter {
// set up memory // set up memory
if (!this.options.noMemory) { if (!this.options.noMemory) {
const initial: U64 = this.memoryOffset.clone(); const initial = this.memoryOffset.clone();
if (this.options.target == Target.WASM64) if (this.options.target == Target.WASM64)
this.module.addGlobal("HEAP_BASE", NativeType.I64, false, this.module.createI64(initial.lo, initial.hi)); this.module.addGlobal("HEAP_BASE", NativeType.I64, false, this.module.createI64(initial.lo, initial.hi));
else else
this.module.addGlobal("HEAP_BASE", NativeType.I32, false, this.module.createI32(initial.lo)); this.module.addGlobal("HEAP_BASE", NativeType.I32, false, this.module.createI32(initial.lo));
// determine initial page size // determine initial page size
const initialOverlaps: U64 = initial.clone(); const initialOverlaps = initial.clone();
initialOverlaps.and32(0xffff); initialOverlaps.and32(0xffff);
if (!initialOverlaps.isZero) { if (!initialOverlaps.isZero) {
initial.or32(0xffff); initial.or32(0xffff);
initial.add32(1); initial.add32(1);
} }
initial.shru32(16); // now is initial size in 64k pages initial.shru32(16); // now is initial size in 64k pages
this.module.setMemory(initial.toI32(), Module.MAX_MEMORY_WASM32 /* TODO: not WASM64 compatible yet */, this.memorySegments, this.options.target, "memory"); this.module.setMemory(initial.toI32(), Module.MAX_MEMORY_WASM32 /* TODO: not WASM64 compatible yet */, this.memorySegments, this.options.target, "memory");
} }
return this.module; return this.module;
} }
@ -253,8 +249,8 @@ export class Compiler extends DiagnosticEmitter {
// sources // sources
compileSourceByPath(normalizedPath: string, reportNode: Node): void { compileSourceByPath(normalizedPath: string, reportNode: Node): void {
for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i) { for (let i = 0, k = this.program.sources.length; i < k; ++i) {
const importedSource: Source = this.program.sources[i]; const importedSource = this.program.sources[i];
if (importedSource.normalizedPath == normalizedPath) { if (importedSource.normalizedPath == normalizedPath) {
this.compileSource(importedSource); this.compileSource(importedSource);
return; return;
@ -268,24 +264,23 @@ export class Compiler extends DiagnosticEmitter {
return; return;
this.files.add(source.normalizedPath); this.files.add(source.normalizedPath);
const isEntry: bool = source.isEntry; const noTreeShaking = this.options.noTreeShaking;
const noTreeShaking: bool = this.options.noTreeShaking; for (let i = 0, k = source.statements.length; i < k; ++i) {
for (let i: i32 = 0, k: i32 = source.statements.length; i < k; ++i) {
const statement: Statement = source.statements[i]; const statement: Statement = source.statements[i];
switch (statement.kind) { switch (statement.kind) {
case NodeKind.CLASS: case NodeKind.CLASS:
if ((noTreeShaking || isEntry && hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>statement).modifiers)) && !(<ClassDeclaration>statement).typeParameters.length) if ((noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>statement).modifiers)) && !(<ClassDeclaration>statement).typeParameters.length)
this.compileClassDeclaration(<ClassDeclaration>statement, []); this.compileClassDeclaration(<ClassDeclaration>statement, []);
break; break;
case NodeKind.ENUM: case NodeKind.ENUM:
if (noTreeShaking || isEntry && hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>statement).modifiers)) if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>statement).modifiers))
this.compileEnumDeclaration(<EnumDeclaration>statement); this.compileEnumDeclaration(<EnumDeclaration>statement);
break; break;
case NodeKind.FUNCTION: case NodeKind.FUNCTION:
if ((noTreeShaking || isEntry && hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>statement).modifiers)) && !(<FunctionDeclaration>statement).typeParameters.length) if ((noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>statement).modifiers)) && !(<FunctionDeclaration>statement).typeParameters.length)
this.compileFunctionDeclaration(<FunctionDeclaration>statement, []); this.compileFunctionDeclaration(<FunctionDeclaration>statement, []);
break; break;
@ -294,28 +289,29 @@ export class Compiler extends DiagnosticEmitter {
break; break;
case NodeKind.NAMESPACE: case NodeKind.NAMESPACE:
if (noTreeShaking || isEntry && hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>statement).modifiers)) if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>statement).modifiers))
this.compileNamespaceDeclaration(<NamespaceDeclaration>statement); this.compileNamespaceDeclaration(<NamespaceDeclaration>statement);
break; break;
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
if (noTreeShaking || isEntry && hasModifier(ModifierKind.EXPORT, (<VariableStatement>statement).modifiers)) if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<VariableStatement>statement).modifiers))
this.compileVariableStatement(<VariableStatement>statement); this.compileVariableStatement(<VariableStatement>statement);
break; break;
case NodeKind.EXPORT: case NodeKind.EXPORT:
if ((<ExportStatement>statement).normalizedPath != null) if ((<ExportStatement>statement).normalizedPath != null)
this.compileSourceByPath(<string>(<ExportStatement>statement).normalizedPath, <StringLiteralExpression>(<ExportStatement>statement).path); this.compileSourceByPath(<string>(<ExportStatement>statement).normalizedPath, <StringLiteralExpression>(<ExportStatement>statement).path);
if (noTreeShaking || isEntry) if (noTreeShaking || source.isEntry)
this.compileExportStatement(<ExportStatement>statement); this.compileExportStatement(<ExportStatement>statement);
break; break;
// otherwise a top-level statement that is part of the start function's body // otherwise a top-level statement that is part of the start function's body
default: { default: {
const previousFunction: Function = this.currentFunction; const previousFunction = this.currentFunction;
this.currentFunction = this.startFunction; this.currentFunction = this.startFunction;
const expr: ExpressionRef = this.compileStatement(statement); const expr = this.compileStatement(statement);
if (!this.module.noEmit) this.startFunctionBody.push(expr); if (!this.module.noEmit)
this.startFunctionBody.push(expr);
this.currentFunction = previousFunction; this.currentFunction = previousFunction;
break; break;
} }
@ -326,7 +322,7 @@ export class Compiler extends DiagnosticEmitter {
// globals // globals
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null { compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null {
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName); const element = this.program.elements.get(declaration.internalName);
if (!element || element.kind != ElementKind.GLOBAL) if (!element || element.kind != ElementKind.GLOBAL)
throw new Error("global expected"); throw new Error("global expected");
if (!this.compileGlobal(<Global>element)) // reports if (!this.compileGlobal(<Global>element)) // reports
@ -344,7 +340,7 @@ export class Compiler extends DiagnosticEmitter {
if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetConstant(this, global))) if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetConstant(this, global)))
return true; return true;
const declaration: VariableLikeDeclarationStatement | null = global.declaration; const declaration = global.declaration;
let initExpr: ExpressionRef = 0; let initExpr: ExpressionRef = 0;
if (!global.type) { // infer type if (!global.type) { // infer type
@ -366,8 +362,8 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("declaration expected"); throw new Error("declaration expected");
} }
const nativeType: NativeType = global.type.toNativeType(); const nativeType = global.type.toNativeType();
let initializeInStart: bool = false; let initializeInStart = false;
if (global.hasConstantValue) { if (global.hasConstantValue) {
if (global.type.isLongInteger) if (global.type.isLongInteger)
@ -378,7 +374,7 @@ export class Compiler extends DiagnosticEmitter {
initExpr = this.module.createF64(global.constantFloatValue); initExpr = this.module.createF64(global.constantFloatValue);
else if (global.type.isSmallInteger) { else if (global.type.isSmallInteger) {
if (global.type.isSignedInteger) { if (global.type.isSignedInteger) {
const shift: i32 = global.type.smallIntegerShift; const shift = global.type.smallIntegerShift;
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0); initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0);
} else } else
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & global.type.smallIntegerMask: 0); initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & global.type.smallIntegerMask: 0);
@ -403,10 +399,10 @@ export class Compiler extends DiagnosticEmitter {
} else } else
throw new Error("declaration expected"); throw new Error("declaration expected");
const internalName: string = global.internalName; const internalName = global.internalName;
if (initializeInStart) { if (initializeInStart) {
this.module.addGlobal(internalName, nativeType, true, global.type.toNativeZero(this.module)); this.module.addGlobal(internalName, nativeType, true, global.type.toNativeZero(this.module));
const setExpr: ExpressionRef = this.module.createSetGlobal(internalName, initExpr); const setExpr = this.module.createSetGlobal(internalName, initExpr);
if (!this.module.noEmit) if (!this.module.noEmit)
this.startFunctionBody.push(setExpr); this.startFunctionBody.push(setExpr);
} else { } else {
@ -439,7 +435,7 @@ export class Compiler extends DiagnosticEmitter {
// enums // enums
compileEnumDeclaration(declaration: EnumDeclaration): void { compileEnumDeclaration(declaration: EnumDeclaration): void {
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName); const element = this.program.elements.get(declaration.internalName);
if (!element || element.kind != ElementKind.ENUM) if (!element || element.kind != ElementKind.ENUM)
throw new Error("enum expected"); throw new Error("enum expected");
this.compileEnum(<Enum>element); this.compileEnum(<Enum>element);
@ -454,13 +450,13 @@ export class Compiler extends DiagnosticEmitter {
for (let [key, member] of element.members) { for (let [key, member] of element.members) {
if (member.kind != ElementKind.ENUMVALUE) if (member.kind != ElementKind.ENUMVALUE)
continue; continue;
const val: EnumValue = <EnumValue>member; const val = <EnumValue>member;
if (val.hasConstantValue) { if (val.hasConstantValue) {
this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue)); this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
} else if (val.declaration) { } else if (val.declaration) {
const declaration: EnumValueDeclaration = val.declaration; const declaration = val.declaration;
let initExpr: ExpressionRef; let initExpr: ExpressionRef;
let initInStart: bool = false; let initInStart = false;
if (declaration.value) { if (declaration.value) {
initExpr = this.compileExpression(<Expression>declaration.value, Type.i32); initExpr = this.compileExpression(<Expression>declaration.value, Type.i32);
if (!this.module.noEmit && _BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (!this.module.noEmit && _BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
@ -487,7 +483,7 @@ export class Compiler extends DiagnosticEmitter {
} }
if (initInStart) { if (initInStart) {
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0)); this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0));
const setExpr: ExpressionRef = this.module.createSetGlobal(val.internalName, initExpr); const setExpr = this.module.createSetGlobal(val.internalName, initExpr);
if (!this.module.noEmit) if (!this.module.noEmit)
this.startFunctionBody.push(setExpr); this.startFunctionBody.push(setExpr);
} else { } else {
@ -510,11 +506,11 @@ export class Compiler extends DiagnosticEmitter {
// functions // functions
compileFunctionDeclaration(declaration: FunctionDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void { compileFunctionDeclaration(declaration: FunctionDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
const internalName: string = declaration.internalName; const internalName = declaration.internalName;
const element: Element | null = <Element | null>this.program.elements.get(internalName); const element = this.program.elements.get(internalName);
if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE) if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE)
throw new Error("unexpected missing function"); throw new Error("function expected");
const instance: Function | null = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode); const instance = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
if (!instance) if (!instance)
return; return;
if (isModuleExport(instance, declaration)) if (isModuleExport(instance, declaration))
@ -522,7 +518,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileFunctionUsingTypeArguments(prototype: FunctionPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Function | null { compileFunctionUsingTypeArguments(prototype: FunctionPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Function | null {
const instance: Function | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode); // reports const instance = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode); // reports
if (!instance) if (!instance)
return null; return null;
return this.compileFunction(instance) ? instance : null; return this.compileFunction(instance) ? instance : null;
@ -532,7 +528,7 @@ export class Compiler extends DiagnosticEmitter {
if (instance.isCompiled) if (instance.isCompiled)
return true; return true;
const declaration: FunctionDeclaration | null = instance.prototype.declaration; const declaration = instance.prototype.declaration;
if (!declaration) if (!declaration)
throw new Error("declaration expected"); // built-ins are not compiled here throw new Error("declaration expected"); // built-ins are not compiled here
@ -552,59 +548,43 @@ export class Compiler extends DiagnosticEmitter {
// compile statements // compile statements
let stmts: ExpressionRef[] | null = null; let stmts: ExpressionRef[] | null = null;
if (!instance.isDeclared) { if (!instance.isDeclared) {
const previousFunction: Function = this.currentFunction; const previousFunction = this.currentFunction;
this.currentFunction = instance; this.currentFunction = instance;
stmts = this.compileStatements(<Statement[]>declaration.statements); stmts = this.compileStatements(<Statement[]>declaration.statements);
this.currentFunction = previousFunction; this.currentFunction = previousFunction;
} }
// create the function type // create the function type
let k: i32 = instance.parameters.length; let k = instance.parameters.length;
const nativeResultType: NativeType = instance.returnType.toNativeType(); const nativeResultType = instance.returnType.toNativeType();
const nativeParamTypes: NativeType[] = new Array(k); const nativeParamTypes = new Array<NativeType>(k);
const signatureNameParts: string[] = new Array(k + 1); const signatureNameParts = new Array<string>(k + 1);
for (let i: i32 = 0; i < k; ++i) { for (let i = 0; i < k; ++i) {
nativeParamTypes[i] = instance.parameters[i].type.toNativeType(); nativeParamTypes[i] = instance.parameters[i].type.toNativeType();
signatureNameParts[i] = instance.parameters[i].type.toSignatureName(); signatureNameParts[i] = instance.parameters[i].type.toSignatureName();
} }
signatureNameParts[k] = instance.returnType.toSignatureName(); signatureNameParts[k] = instance.returnType.toSignatureName();
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeResultType, nativeParamTypes); let typeRef = this.module.getFunctionTypeBySignature(nativeResultType, nativeParamTypes);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes); typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes);
// create the function // create the function
const internalName: string = instance.internalName;
if (instance.isDeclared) { // TODO: use parent namespace as externalModuleName, if applicable if (instance.isDeclared) { // TODO: use parent namespace as externalModuleName, if applicable
this.module.addFunctionImport(internalName, "env", declaration.name.name, typeRef); this.module.addFunctionImport(instance.internalName, "env", declaration.name.name, typeRef);
} else { } else {
this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None)); this.module.addFunction(instance.internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None));
} }
instance.finalize(); instance.finalize();
return true; return true;
} }
// compilePropertyUsingTypeArguments(prototype: PropertyPrototype, contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Function | null {
// let getter: Function | null = null;
// let setter: Function | null = null;
// if (prototype.getterPrototype) {
// getter = prototype.getterPrototype.resolve([], contextualTypeArguments); // reports
// if (prototype.setterPrototype)
// setter = prototype.setterPrototype.resolve([], contextualTypeArguments); // reports
// }
// }
// compileProperty(instance: Property): bool {
// }
// namespaces // namespaces
compileNamespaceDeclaration(declaration: NamespaceDeclaration): void { compileNamespaceDeclaration(declaration: NamespaceDeclaration): void {
const members: Statement[] = declaration.members; const members = declaration.members;
const noTreeShaking: bool = this.options.noTreeShaking; const noTreeShaking = this.options.noTreeShaking;
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) { for (let i = 0, k = members.length; i < k; ++i) {
const member: Statement = members[i]; const member = members[i];
switch (member.kind) { switch (member.kind) {
case NodeKind.CLASS: case NodeKind.CLASS:
@ -638,7 +618,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
default: default:
throw new Error("unexpected namespace member"); throw new Error("namespace member expected");
} }
} }
} }
@ -647,7 +627,7 @@ export class Compiler extends DiagnosticEmitter {
if (!ns.members) if (!ns.members)
return; return;
const noTreeShaking: bool = this.options.noTreeShaking; const noTreeShaking = this.options.noTreeShaking;
for (let [name, element] of ns.members) { for (let [name, element] of ns.members) {
switch (element.kind) { switch (element.kind) {
@ -679,11 +659,11 @@ export class Compiler extends DiagnosticEmitter {
// exports // exports
compileExportStatement(statement: ExportStatement): void { compileExportStatement(statement: ExportStatement): void {
const members: ExportMember[] = statement.members; const members = statement.members;
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) { for (let i = 0, k = members.length; i < k; ++i) {
const member: ExportMember = members[i]; const member = members[i];
const internalExportName: string = statement.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name; const internalExportName = statement.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
const element: Element | null = <Element | null>this.program.exports.get(internalExportName); const element = this.program.exports.get(internalExportName);
if (!element) // reported in Program#initialize if (!element) // reported in Program#initialize
continue; continue;
switch (element.kind) { switch (element.kind) {
@ -699,7 +679,7 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.FUNCTION_PROTOTYPE: case ElementKind.FUNCTION_PROTOTYPE:
if (!(<FunctionPrototype>element).isGeneric) { if (!(<FunctionPrototype>element).isGeneric) {
const functionInstance: Function | null = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []); const functionInstance = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
if (functionInstance && statement.range.source.isEntry) if (functionInstance && statement.range.source.isEntry)
this.module.addFunctionExport(functionInstance.internalName, member.externalIdentifier.name); this.module.addFunctionExport(functionInstance.internalName, member.externalIdentifier.name);
} }
@ -724,15 +704,15 @@ export class Compiler extends DiagnosticEmitter {
// classes // classes
compileClassDeclaration(declaration: ClassDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void { compileClassDeclaration(declaration: ClassDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
const internalName: string = declaration.internalName; const internalName = declaration.internalName;
const element: Element | null = <Element | null>this.program.elements.get(internalName); const element = this.program.elements.get(internalName);
if (!element || element.kind != ElementKind.CLASS_PROTOTYPE) if (!element || element.kind != ElementKind.CLASS_PROTOTYPE)
throw new Error("unexpected missing class"); throw new Error("class expected");
this.compileClassUsingTypeArguments(<ClassPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode); this.compileClassUsingTypeArguments(<ClassPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode);
} }
compileClassUsingTypeArguments(prototype: ClassPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void { compileClassUsingTypeArguments(prototype: ClassPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
const instance: Class | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode); const instance = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode);
if (!instance) if (!instance)
return; return;
this.compileClass(instance); this.compileClass(instance);
@ -754,7 +734,7 @@ export class Compiler extends DiagnosticEmitter {
this.memoryOffset.or32(7); this.memoryOffset.or32(7);
this.memoryOffset.add32(1); this.memoryOffset.add32(1);
} }
const segment: MemorySegment = MemorySegment.create(buffer, this.memoryOffset.clone()); const segment = MemorySegment.create(buffer, this.memoryOffset.clone());
this.memorySegments.push(segment); this.memorySegments.push(segment);
this.memoryOffset.add32(buffer.length); this.memoryOffset.add32(buffer.length);
return segment; return segment;
@ -801,31 +781,32 @@ export class Compiler extends DiagnosticEmitter {
case NodeKind.TRY: case NodeKind.TRY:
return this.compileTryStatement(<TryStatement>statement); return this.compileTryStatement(<TryStatement>statement);
case NodeKind.TYPEDECLARATION:
if (this.currentFunction == this.startFunction)
return this.module.createNop();
break; // must be top-level; function bodies are not initialized
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
return this.compileVariableStatement(<VariableStatement>statement); return this.compileVariableStatement(<VariableStatement>statement);
case NodeKind.WHILE: case NodeKind.WHILE:
return this.compileWhileStatement(<WhileStatement>statement); return this.compileWhileStatement(<WhileStatement>statement);
case NodeKind.TYPEDECLARATION:
if (this.currentFunction == this.startFunction)
return this.module.createNop();
// fall-through: must be top-level; function bodies are not initialized
default:
throw new Error("statement expected");
} }
this.error(DiagnosticCode.Operation_not_supported, statement.range);
throw new Error("unexpected statement kind");
} }
compileStatements(statements: Statement[]): ExpressionRef[] { compileStatements(statements: Statement[]): ExpressionRef[] {
let i: i32 = 0, k: i32 = statements.length; const k = statements.length;
const stmts: ExpressionRef[] = new Array(k); const stmts = new Array<ExpressionRef>(k);
for (; i < k; ++i) for (let i = 0; i < k; ++i)
stmts[i] = this.compileStatement(statements[i]); stmts[i] = this.compileStatement(statements[i]);
return stmts; // array of 0-es in noEmit-mode return stmts; // array of 0-es in noEmit-mode
} }
compileBlockStatement(statement: BlockStatement): ExpressionRef { compileBlockStatement(statement: BlockStatement): ExpressionRef {
const statements: Statement[] = statement.statements; const statements = statement.statements;
if (statements.length == 0) if (statements.length == 0)
return this.module.createNop(); return this.module.createNop();
if (statements.length == 1) if (statements.length == 1)
@ -838,9 +819,10 @@ export class Compiler extends DiagnosticEmitter {
this.error(DiagnosticCode.Operation_not_supported, statement.label.range); this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
const context: string | null = this.currentFunction.breakContext; const context = this.currentFunction.breakContext;
if (context != null) if (context != null)
return this.module.createBreak("break|" + (<string>context)); return this.module.createBreak("break|" + (<string>context));
this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range); this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
@ -850,20 +832,21 @@ export class Compiler extends DiagnosticEmitter {
this.error(DiagnosticCode.Operation_not_supported, statement.label.range); this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
const context: string | null = this.currentFunction.breakContext; const context = this.currentFunction.breakContext;
if (context != null && !this.disallowContinue) if (context != null && !this.disallowContinue)
return this.module.createBreak("continue|" + (<string>context)); return this.module.createBreak("continue|" + (<string>context));
this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range); this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileDoStatement(statement: DoStatement): ExpressionRef { compileDoStatement(statement: DoStatement): ExpressionRef {
const label: string = this.currentFunction.enterBreakContext(); const label = this.currentFunction.enterBreakContext();
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition = this.compileExpression(statement.condition, Type.i32);
const body: ExpressionRef = this.compileStatement(statement.statement); const body = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
const breakLabel: string = "break|" + label; const breakLabel = "break|" + label;
const continueLabel: string = "continue|" + label; const continueLabel = "continue|" + label;
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel, this.module.createLoop(continueLabel,
this.module.createBlock(null, [ this.module.createBlock(null, [
@ -878,7 +861,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileExpressionStatement(statement: ExpressionStatement): ExpressionRef { compileExpressionStatement(statement: ExpressionStatement): ExpressionRef {
let expr: ExpressionRef = this.compileExpression(statement.expression, Type.void, ConversionKind.NONE); let expr = this.compileExpression(statement.expression, Type.void, ConversionKind.NONE);
if (this.currentType != Type.void) { if (this.currentType != Type.void) {
expr = this.module.createDrop(expr); expr = this.module.createDrop(expr);
this.currentType = Type.void; this.currentType = Type.void;
@ -887,18 +870,18 @@ export class Compiler extends DiagnosticEmitter {
} }
compileForStatement(statement: ForStatement): ExpressionRef { compileForStatement(statement: ForStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext(); const context = this.currentFunction.enterBreakContext();
const variableWasLocal: bool = this.variableIsLocal; const variableWasLocal = this.variableIsLocal;
if (this.currentFunction == this.startFunction) if (this.currentFunction == this.startFunction)
this.variableIsLocal = true; this.variableIsLocal = true;
const initializer: ExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop(); const initializer = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop();
this.variableIsLocal = variableWasLocal; this.variableIsLocal = variableWasLocal;
const condition: ExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1); const condition = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1);
const incrementor: ExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop(); const incrementor = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
const body: ExpressionRef = this.compileStatement(statement.statement); const body = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
const continueLabel: string = "continue|" + context; const continueLabel = "continue|" + context;
const breakLabel: string = "break|" + context; const breakLabel = "break|" + context;
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
initializer, initializer,
this.module.createLoop(continueLabel, this.module.createBlock(null, [ this.module.createLoop(continueLabel, this.module.createBlock(null, [
@ -912,38 +895,38 @@ export class Compiler extends DiagnosticEmitter {
} }
compileIfStatement(statement: IfStatement): ExpressionRef { compileIfStatement(statement: IfStatement): ExpressionRef {
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition = this.compileExpression(statement.condition, Type.i32);
const ifTrue: ExpressionRef = this.compileStatement(statement.ifTrue); const ifTrue = this.compileStatement(statement.ifTrue);
const ifFalse: ExpressionRef = statement.ifFalse ? this.compileStatement(<Statement>statement.ifFalse) : 0; const ifFalse = statement.ifFalse ? this.compileStatement(<Statement>statement.ifFalse) : <ExpressionRef>0;
return this.module.createIf(condition, ifTrue, ifFalse); return this.module.createIf(condition, ifTrue, ifFalse);
} }
compileReturnStatement(statement: ReturnStatement): ExpressionRef { compileReturnStatement(statement: ReturnStatement): ExpressionRef {
if (this.currentFunction) { if (this.currentFunction) {
const expression: ExpressionRef = statement.value ? this.compileExpression(<Expression>statement.value, this.currentFunction.returnType) : 0; const expression = statement.value ? this.compileExpression(<Expression>statement.value, this.currentFunction.returnType) : <ExpressionRef>0;
return this.module.createReturn(expression); return this.module.createReturn(expression);
} }
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileSwitchStatement(statement: SwitchStatement): ExpressionRef { compileSwitchStatement(statement: SwitchStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext(); const context = this.currentFunction.enterBreakContext();
const previousDisallowContinue: bool = this.disallowContinue; const previousDisallowContinue = this.disallowContinue;
this.disallowContinue = true; this.disallowContinue = true;
// introduce a local for evaluating the condition (exactly once) // introduce a local for evaluating the condition (exactly once)
const tempLocal: Local = this.currentFunction.getTempLocal(Type.i32); const tempLocal = this.currentFunction.getTempLocal(Type.i32);
let i: i32, k: i32 = statement.cases.length; let i: i32, k = statement.cases.length;
// prepend initializer to inner block // prepend initializer to inner block
const breaks: ExpressionRef[] = new Array(1 + k); const breaks = new Array<ExpressionRef>(1 + k);
breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.condition, Type.i32)); // initializer breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.condition, Type.i32)); // initializer
// make one br_if per (possibly dynamic) labeled case (binaryen optimizes to br_table where possible) // make one br_if per (possibly dynamic) labeled case (binaryen optimizes to br_table where possible)
let breakIndex: i32 = 1; let breakIndex = 1;
let defaultIndex: i32 = -1; let defaultIndex = -1;
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
const case_: SwitchCase = statement.cases[i]; const case_ = statement.cases[i];
if (case_.label) { if (case_.label) {
breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "|" + context, breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "|" + context,
this.module.createBinary(BinaryOp.EqI32, this.module.createBinary(BinaryOp.EqI32,
@ -964,16 +947,14 @@ export class Compiler extends DiagnosticEmitter {
) + "|" + context); ) + "|" + context);
// nest blocks in order // nest blocks in order
let currentBlock: ExpressionRef = this.module.createBlock("case0|" + context, breaks, NativeType.None); let currentBlock = this.module.createBlock("case0|" + context, breaks, NativeType.None);
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
const case_: SwitchCase = statement.cases[i]; const case_ = statement.cases[i];
const nextLabel: string = i == k - 1 const nextLabel = i == k - 1 ? "break|" + context : "case" + (i + 1).toString(10) + "|" + context;
? "break|" + context const l = case_.statements.length;
: "case" + (i + 1).toString(10) + "|" + context; const body = new Array<ExpressionRef>(1 + l);
const l: i32 = case_.statements.length;
const body: ExpressionRef[] = new Array(1 + l);
body[0] = currentBlock; body[0] = currentBlock;
for (let j: i32 = 0; j < l; ++j) for (let j = 0; j < l; ++j)
body[j + 1] = this.compileStatement(case_.statements[j]); body[j + 1] = this.compileStatement(case_.statements[j]);
currentBlock = this.module.createBlock(nextLabel, body, NativeType.None); currentBlock = this.module.createBlock(nextLabel, body, NativeType.None);
} }
@ -994,20 +975,20 @@ export class Compiler extends DiagnosticEmitter {
} }
compileVariableStatement(statement: VariableStatement): ExpressionRef { compileVariableStatement(statement: VariableStatement): ExpressionRef {
const declarations: VariableDeclaration[] = statement.declarations; const declarations = statement.declarations;
// top-level variables become globals // top-level variables become globals
if (this.currentFunction == this.startFunction && !this.variableIsLocal) { if (this.currentFunction == this.startFunction && !this.variableIsLocal) {
const isConst: bool = hasModifier(ModifierKind.CONST, statement.modifiers); const isConst = hasModifier(ModifierKind.CONST, statement.modifiers);
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) for (let i = 0, k = declarations.length; i < k; ++i)
this.compileGlobalDeclaration(declarations[i], isConst); this.compileGlobalDeclaration(declarations[i], isConst);
return this.module.createNop(); return this.module.createNop();
} }
// other variables become locals // other variables become locals
const initializers: ExpressionRef[] = new Array(); const initializers = new Array<ExpressionRef>();
for (let i: i32 = 0, k = declarations.length; i < k; ++i) { for (let i = 0, k = declarations.length; i < k; ++i) {
const declaration: VariableDeclaration = declarations[i]; const declaration = declarations[i];
const name: string = declaration.name.name; const name = declaration.name.name;
let type: Type | null = null; let type: Type | null = null;
let init: ExpressionRef = 0; let init: ExpressionRef = 0;
if (declaration.type) { if (declaration.type) {
@ -1036,11 +1017,11 @@ export class Compiler extends DiagnosticEmitter {
} }
compileWhileStatement(statement: WhileStatement): ExpressionRef { compileWhileStatement(statement: WhileStatement): ExpressionRef {
const label: string = this.currentFunction.enterBreakContext(); const label = this.currentFunction.enterBreakContext();
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition = this.compileExpression(statement.condition, Type.i32);
const breakLabel: string = "break|" + label; const breakLabel = "break|" + label;
const continueLabel: string = "continue|" + label; const continueLabel = "continue|" + label;
const body: ExpressionRef = this.compileStatement(statement.statement); const body = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel, this.module.createLoop(continueLabel,
@ -1113,7 +1094,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
default: default:
throw new Error("unexpected expression kind"); throw new Error("expression expected");
} }
if (conversionKind != ConversionKind.NONE && this.currentType != contextualType) { if (conversionKind != ConversionKind.NONE && this.currentType != contextualType) {
@ -1124,18 +1105,17 @@ export class Compiler extends DiagnosticEmitter {
} }
precomputeExpression(expression: Expression, contextualType: Type, conversionKind: ConversionKind = ConversionKind.IMPLICIT): ExpressionRef { precomputeExpression(expression: Expression, contextualType: Type, conversionKind: ConversionKind = ConversionKind.IMPLICIT): ExpressionRef {
const expr: ExpressionRef = this.compileExpression(expression, contextualType, conversionKind); return this.precomputeExpressionRef(this.compileExpression(expression, contextualType, conversionKind));
return this.precomputeExpressionRef(expr);
} }
precomputeExpressionRef(expr: ExpressionRef): ExpressionRef { precomputeExpressionRef(expr: ExpressionRef): ExpressionRef {
const nativeType: NativeType = this.currentType.toNativeType(); const nativeType = this.currentType.toNativeType();
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeType, []); let typeRef = this.module.getFunctionTypeBySignature(nativeType, []);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType(this.currentType.toSignatureName(), nativeType, []); typeRef = this.module.addFunctionType(this.currentType.toSignatureName(), nativeType, []);
const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr); const funcRef = this.module.addFunction("__precompute", typeRef, [], expr);
this.module.runPasses([ "precompute" ], funcRef); this.module.runPasses([ "precompute" ], funcRef);
const ret: ExpressionRef = _BinaryenFunctionGetBody(funcRef); const ret = _BinaryenFunctionGetBody(funcRef);
this.module.removeFunction("__precompute"); this.module.removeFunction("__precompute");
// TODO: also remove the function type somehow if no longer used or make the C-API accept // TODO: also remove the function type somehow if no longer used or make the C-API accept
// a `null` typeRef, using an implicit type. // a `null` typeRef, using an implicit type.
@ -1156,11 +1136,11 @@ export class Compiler extends DiagnosticEmitter {
if (toType.kind == TypeKind.VOID) if (toType.kind == TypeKind.VOID)
return this.module.createDrop(expr); return this.module.createDrop(expr);
const fromFloat: bool = fromType.isAnyFloat; const fromFloat = fromType.isAnyFloat;
const toFloat: bool = toType.isAnyFloat; const toFloat = toType.isAnyFloat;
const mod: Module = this.module; const mod = this.module;
let losesInformation: bool = false; let losesInformation = false;
if (fromFloat) { if (fromFloat) {
@ -1306,7 +1286,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef { compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports const toType = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (!toType) if (!toType)
return this.module.createUnreachable(); return this.module.createUnreachable();
return this.compileExpression(expression.expression, toType, ConversionKind.EXPLICIT); return this.compileExpression(expression.expression, toType, ConversionKind.EXPLICIT);
@ -1669,16 +1649,16 @@ export class Compiler extends DiagnosticEmitter {
break; break;
case ElementKind.PROPERTY: case ElementKind.PROPERTY:
const setterPrototype: FunctionPrototype | null = (<Property>element).setterPrototype; const setterPrototype = (<Property>element).setterPrototype;
if (setterPrototype) { if (setterPrototype) {
const setterInstance: Function | null = setterPrototype.resolve(); // reports const setterInstance = setterPrototype.resolve(); // reports
if (setterInstance) { if (setterInstance) {
if (contextualType == Type.void) { // just set if dropped anyway if (contextualType == Type.void) { // just set if dropped anyway
return this.compileCall(setterInstance, [ valueExpression ], expression); return this.compileCall(setterInstance, [ valueExpression ], expression);
} else { // otherwise do a set followed by a get } else { // otherwise do a set followed by a get
const getterPrototype: FunctionPrototype | null = (<Property>element).getterPrototype; const getterPrototype = (<Property>element).getterPrototype;
if (getterPrototype) { if (getterPrototype) {
const getterInstance: Function | null = getterPrototype.resolve(); // reports const getterInstance = getterPrototype.resolve(); // reports
if (getterInstance) { if (getterInstance) {
return this.module.createBlock(null, [ return this.module.createBlock(null, [
this.compileCall(setterInstance, [ valueExpression ], expression), this.compileCall(setterInstance, [ valueExpression ], expression),
@ -1749,7 +1729,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType); return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
} }
// TODO: fields, setters // TODO: fields, (setters)
throw new Error("not implemented"); throw new Error("not implemented");
} }
@ -1774,24 +1754,24 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
if (element.kind == ElementKind.FUNCTION_PROTOTYPE) { if (element.kind == ElementKind.FUNCTION_PROTOTYPE) {
const functionPrototype: FunctionPrototype = <FunctionPrototype>element; const functionPrototype = <FunctionPrototype>element;
let functionInstance: Function | null = null; let functionInstance: Function | null = null;
if (functionPrototype.isBuiltIn) { if (functionPrototype.isBuiltIn) {
const k: i32 = expression.typeArguments.length; const k = expression.typeArguments.length;
const resolvedTypeArguments: Type[] = new Array(k); const resolvedTypeArguments = new Array<Type>(k);
sb.length = 0; sb.length = 0;
for (let i: i32 = 0; i < k; ++i) { for (let i = 0; i < k; ++i) {
let resolvedType: Type | null = this.program.resolveType(expression.typeArguments[i], this.currentFunction.contextualTypeArguments, true); // reports let resolvedType = this.program.resolveType(expression.typeArguments[i], this.currentFunction.contextualTypeArguments, true); // reports
if (!resolvedType) if (!resolvedType)
return this.module.createUnreachable(); return this.module.createUnreachable();
resolvedTypeArguments[i] = resolvedType; resolvedTypeArguments[i] = resolvedType;
sb.push(resolvedType.toString()); sb.push(resolvedType.toString());
} }
functionInstance = <Function | null>functionPrototype.instances.get(sb.join(",")); functionInstance = functionPrototype.instances.get(sb.join(","));
if (!functionInstance) { if (!functionInstance) {
this.currentType = contextualType; this.currentType = contextualType;
let expr: ExpressionRef = compileBuiltinCall(this, functionPrototype, resolvedTypeArguments, expression.arguments, expression); let expr = compileBuiltinCall(this, functionPrototype, resolvedTypeArguments, expression.arguments, expression);
if (!expr) { if (!expr) {
this.error(DiagnosticCode.Operation_not_supported, expression.range); this.error(DiagnosticCode.Operation_not_supported, expression.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
@ -1814,9 +1794,9 @@ export class Compiler extends DiagnosticEmitter {
compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): ExpressionRef { compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
// validate and compile arguments // validate and compile arguments
const parameters: Parameter[] = functionInstance.parameters; const parameters = functionInstance.parameters;
const parameterCount: i32 = parameters.length; const parameterCount = parameters.length;
const argumentCount: i32 = argumentExpressions.length; const argumentCount = argumentExpressions.length;
if (argumentExpressions.length > parameterCount) { // too many arguments if (argumentExpressions.length > parameterCount) { // too many arguments
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range,
(functionInstance.isInstance ? parameterCount - 1 : parameterCount).toString(10), (functionInstance.isInstance ? parameterCount - 1 : parameterCount).toString(10),
@ -1824,12 +1804,12 @@ export class Compiler extends DiagnosticEmitter {
); );
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
const operands: ExpressionRef[] = new Array(parameterCount); const operands = new Array<ExpressionRef>(parameterCount);
for (let i: i32 = 0; i < parameterCount; ++i) { for (let i = 0; i < parameterCount; ++i) {
if (argumentExpressions.length > i) { if (argumentExpressions.length > i) {
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type); operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type);
} else { } else {
const initializer: Expression | null = parameters[i].initializer; const initializer = parameters[i].initializer;
if (initializer) { // omitted, uses initializer if (initializer) { // omitted, uses initializer
// FIXME: here, the initializer is compiled in the caller's scope. // FIXME: here, the initializer is compiled in the caller's scope.
// a solution could be to use a stub for each possible overload, calling the // a solution could be to use a stub for each possible overload, calling the
@ -1859,7 +1839,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef { compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports const element = this.program.resolveElement(expression.expression, this.currentFunction); // reports
if (!element) if (!element)
return this.module.createUnreachable(); return this.module.createUnreachable();
throw new Error("not implemented"); throw new Error("not implemented");
@ -1900,7 +1880,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports const element = this.program.resolveElement(expression, this.currentFunction); // reports
if (!element) if (!element)
return this.module.createUnreachable(); return this.module.createUnreachable();
@ -1915,9 +1895,10 @@ export class Compiler extends DiagnosticEmitter {
if (element.isBuiltIn) if (element.isBuiltIn)
return compileBuiltinGetConstant(this, <Global>element); return compileBuiltinGetConstant(this, <Global>element);
const global: Global = <Global>element; const global = <Global>element;
if (!this.compileGlobal(global)) // reports if (!this.compileGlobal(global)) // reports
return this.module.createUnreachable(); return this.module.createUnreachable();
assert(global.type != null);
this.currentType = <Type>global.type; this.currentType = <Type>global.type;
if (global.hasConstantValue) { if (global.hasConstantValue) {
if (global.type == Type.f32) if (global.type == Type.f32)
@ -1929,19 +1910,11 @@ export class Compiler extends DiagnosticEmitter {
else if ((<Type>global.type).isAnyInteger) else if ((<Type>global.type).isAnyInteger)
return this.module.createI32((<I64>global.constantIntegerValue).lo); return this.module.createI32((<I64>global.constantIntegerValue).lo);
else else
throw new Error("unexpected global type"); throw new Error("concrete type expected");
} else } else
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType()); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
} }
// field
// if (element.kind == ElementKind.FIELD)
// throw new Error("not implemented");
// getter
if (element.kind == ElementKind.FUNCTION_PROTOTYPE && (<FunctionPrototype>element).isGetter)
throw new Error("not implemented");
this.error(DiagnosticCode.Operation_not_supported, expression.range); this.error(DiagnosticCode.Operation_not_supported, expression.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
@ -1951,7 +1924,7 @@ export class Compiler extends DiagnosticEmitter {
// case LiteralKind.ARRAY: // case LiteralKind.ARRAY:
case LiteralKind.FLOAT: { case LiteralKind.FLOAT: {
const floatValue: f64 = (<FloatLiteralExpression>expression).value; const floatValue = (<FloatLiteralExpression>expression).value;
if (contextualType == Type.f32) if (contextualType == Type.f32)
return this.module.createF32(<f32>floatValue); return this.module.createF32(<f32>floatValue);
this.currentType = Type.f64; this.currentType = Type.f64;
@ -1959,7 +1932,7 @@ export class Compiler extends DiagnosticEmitter {
} }
case LiteralKind.INTEGER: { case LiteralKind.INTEGER: {
const intValue: I64 = (<IntegerLiteralExpression>expression).value; const intValue = (<IntegerLiteralExpression>expression).value;
if (contextualType == Type.bool && (intValue.isZero || intValue.isOne)) if (contextualType == Type.bool && (intValue.isZero || intValue.isOne))
return this.module.createI32(intValue.isZero ? 0 : 1); return this.module.createI32(intValue.isZero ? 0 : 1);
if (contextualType == Type.f64) if (contextualType == Type.f64)
@ -1995,8 +1968,8 @@ export class Compiler extends DiagnosticEmitter {
} }
compilePropertyAccessExpression(propertyAccess: PropertyAccessExpression, contextualType: Type): ExpressionRef { compilePropertyAccessExpression(propertyAccess: PropertyAccessExpression, contextualType: Type): ExpressionRef {
const expression: Expression = propertyAccess.expression; const expression = propertyAccess.expression;
const propertyName: string = propertyAccess.property.name; const propertyName = propertyAccess.property.name;
// the lhs expression is either 'this', 'super', an identifier or another property access // the lhs expression is either 'this', 'super', an identifier or another property access
let target: Element | null; let target: Element | null;
@ -2027,7 +2000,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
default: default:
throw new Error("unexpected expression kind"); throw new Error("lhs expression expected");
} }
if (!target) if (!target)
return this.module.createUnreachable(); return this.module.createUnreachable();
@ -2088,6 +2061,7 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.GLOBAL: case ElementKind.GLOBAL:
if (!this.compileGlobal(<Global>element)) if (!this.compileGlobal(<Global>element))
return this.module.createUnreachable(); return this.module.createUnreachable();
assert((<Global>element).type != null);
this.currentType = <Type>(<Global>element).type; this.currentType = <Type>(<Global>element).type;
if ((<Global>element).hasConstantValue) if ((<Global>element).hasConstantValue)
return this.currentType== Type.f32 ? this.module.createF32((<Global>element).constantFloatValue) return this.currentType== Type.f32 ? this.module.createF32((<Global>element).constantFloatValue)
@ -2098,9 +2072,9 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType()); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
case ElementKind.PROPERTY: // getter case ElementKind.PROPERTY: // getter
const getterPrototype: FunctionPrototype | null = (<Property>element).getterPrototype; const getterPrototype = (<Property>element).getterPrototype;
if (getterPrototype) { if (getterPrototype) {
const getterInstance: Function | null = getterPrototype.resolve([], this.currentFunction.contextualTypeArguments); const getterInstance = getterPrototype.resolve([], this.currentFunction.contextualTypeArguments);
if (getterInstance) { if (getterInstance) {
return this.compileCall(getterInstance, [], propertyAccess); return this.compileCall(getterInstance, [], propertyAccess);
} else { } else {
@ -2116,20 +2090,20 @@ export class Compiler extends DiagnosticEmitter {
} }
compileTernaryExpression(expression: TernaryExpression, contextualType: Type): ExpressionRef { compileTernaryExpression(expression: TernaryExpression, contextualType: Type): ExpressionRef {
const condition: ExpressionRef = this.compileExpression(expression.condition, Type.i32); const condition = this.compileExpression(expression.condition, Type.i32);
const ifThen: ExpressionRef = this.compileExpression(expression.ifThen, contextualType); const ifThen = this.compileExpression(expression.ifThen, contextualType);
const ifElse: ExpressionRef = this.compileExpression(expression.ifElse, contextualType); const ifElse = this.compileExpression(expression.ifElse, contextualType);
return this.module.createIf(condition, ifThen, ifElse); return this.module.createIf(condition, ifThen, ifElse);
} }
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): ExpressionRef { compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): ExpressionRef {
const operator: Token = expression.operator; const operator = expression.operator;
// make a getter for the expression (also obtains the type) // make a getter for the expression (also obtains the type)
const getValue: ExpressionRef = this.compileExpression(expression.operand, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT); const getValue = this.compileExpression(expression.operand, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
// use a temp local for the intermediate value // use a temp local for the intermediate value
const tempLocal: Local = this.currentFunction.getTempLocal(this.currentType); const tempLocal = this.currentFunction.getTempLocal(this.currentType);
let op: BinaryOp; let op: BinaryOp;
let nativeType: NativeType; let nativeType: NativeType;
@ -2157,7 +2131,7 @@ export class Compiler extends DiagnosticEmitter {
} }
// make a setter that sets the new value (temp value +/- 1) // make a setter that sets the new value (temp value +/- 1)
const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.operand, const setValue = this.compileAssignmentWithValue(expression.operand,
this.module.createBinary(op, this.module.createBinary(op,
this.module.createGetLocal(tempLocal.index, nativeType), this.module.createGetLocal(tempLocal.index, nativeType),
nativeOne nativeOne
@ -2176,7 +2150,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): ExpressionRef { compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): ExpressionRef {
const operandExpression: Expression = expression.operand; const operandExpression = expression.operand;
let operand: ExpressionRef; let operand: ExpressionRef;
let op: UnaryOp; let op: UnaryOp;
@ -2241,7 +2215,7 @@ export class Compiler extends DiagnosticEmitter {
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1)); : this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));
default: default:
throw new Error("not implemented"); throw new Error("unary operator expected");
} }
return this.module.createUnary(op, operand); return this.module.createUnary(op, operand);
} }
@ -2254,7 +2228,7 @@ function isModuleExport(element: Element, declaration: DeclarationStatement): bo
return false; return false;
if (declaration.range.source.isEntry) if (declaration.range.source.isEntry)
return true; return true;
let parentNode: Node | null = declaration.parent; let parentNode = declaration.parent;
if (!parentNode) if (!parentNode)
return false; return false;
if (parentNode.kind == NodeKind.VARIABLE) if (parentNode.kind == NodeKind.VARIABLE)
@ -2262,7 +2236,7 @@ function isModuleExport(element: Element, declaration: DeclarationStatement): bo
return false; return false;
if (parentNode.kind != NodeKind.NAMESPACE && parentNode.kind != NodeKind.CLASS) if (parentNode.kind != NodeKind.NAMESPACE && parentNode.kind != NodeKind.CLASS)
return false; return false;
let parent: Element | null = element.program.elements.get((<DeclarationStatement>parentNode).internalName); let parent = element.program.elements.get((<DeclarationStatement>parentNode).internalName);
if (!parent) if (!parent)
return false; return false;
return isModuleExport(parent, <DeclarationStatement>parentNode); return isModuleExport(parent, <DeclarationStatement>parentNode);

View File

@ -1,8 +1,8 @@
// internal naming scheme // internal naming scheme
export const PATH_DELIMITER: string = "/"; export const PATH_DELIMITER = "/";
export const PARENT_SUBST: string = ".."; export const PARENT_SUBST = "..";
export const GETTER_PREFIX: string = "get_"; export const GETTER_PREFIX = "get:";
export const SETTER_PREFIX: string = "set_"; export const SETTER_PREFIX = "set:";
export const INSTANCE_DELIMITER: string = "#"; export const INSTANCE_DELIMITER = "#";
export const STATIC_DELIMITER: string = "."; export const STATIC_DELIMITER = ".";

View File

@ -250,6 +250,7 @@ export class Program extends DiagnosticEmitter {
return; return;
} }
const prototype = new ClassPrototype(this, declaration.name.name, internalName, declaration); const prototype = new ClassPrototype(this, declaration.name.name, internalName, declaration);
prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
// add program-level alias if annotated as @global // add program-level alias if annotated as @global
@ -433,6 +434,7 @@ export class Program extends DiagnosticEmitter {
return; return;
} }
const enm = new Enum(this, internalName, declaration); const enm = new Enum(this, internalName, declaration);
enm.namespace = namespace;
this.elements.set(internalName, enm); this.elements.set(internalName, enm);
if (namespace) { if (namespace) {
@ -558,6 +560,7 @@ export class Program extends DiagnosticEmitter {
return; return;
} }
const prototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null); const prototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null);
prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
if (hasDecorator("global", declaration.decorators)) { if (hasDecorator("global", declaration.decorators)) {
@ -648,12 +651,12 @@ export class Program extends DiagnosticEmitter {
private initializeInterface(declaration: InterfaceDeclaration, namespace: Element | null = null): void { private initializeInterface(declaration: InterfaceDeclaration, namespace: Element | null = null): void {
const internalName = declaration.internalName; const internalName = declaration.internalName;
const prototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration);
if (this.elements.has(internalName)) { if (this.elements.has(internalName)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
const prototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration);
prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
if (namespace) { if (namespace) {
@ -697,6 +700,7 @@ export class Program extends DiagnosticEmitter {
let namespace = this.elements.get(internalName); let namespace = this.elements.get(internalName);
if (!namespace) { if (!namespace) {
namespace = new Namespace(this, internalName, declaration); namespace = new Namespace(this, internalName, declaration);
namespace.namespace = parentNamespace;
this.elements.set(internalName, namespace); this.elements.set(internalName, namespace);
} }
@ -757,6 +761,7 @@ export class Program extends DiagnosticEmitter {
private initializeType(declaration: TypeDeclaration, namespace: Element | null = null): void { private initializeType(declaration: TypeDeclaration, namespace: Element | null = null): void {
// type aliases are program globals // type aliases are program globals
// TODO: what about namespaced types?
const name = declaration.name.name; const name = declaration.name.name;
if (this.types.has(name) || this.typeAliases.has(name)) { if (this.types.has(name) || this.typeAliases.has(name)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name);
@ -776,6 +781,7 @@ export class Program extends DiagnosticEmitter {
} }
const global = new Global(this, internalName, declaration, null); const global = new Global(this, internalName, declaration, null);
global.namespace = namespace;
this.elements.set(internalName, global); this.elements.set(internalName, global);
if (hasDecorator("global", declaration.decorators)) { if (hasDecorator("global", declaration.decorators)) {
@ -868,17 +874,32 @@ export class Program extends DiagnosticEmitter {
return typeArguments; return typeArguments;
} }
/** Resolves an identifier to the element is refers to. */ /** Resolves an identifier to the element it refers to. */
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function): Element | null { resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function): Element | null {
const name = identifier.name; const name = identifier.name;
const local = contextualFunction.locals.get(name); const local = contextualFunction.locals.get(name);
if (local) if (local)
return local; return local;
let element: Element | null; let element: Element | null;
let namespace: Element | null;
// search parent namespaces if applicable
if (contextualFunction && (namespace = contextualFunction.prototype.namespace)) {
do {
if (element = this.elements.get(namespace.internalName + STATIC_DELIMITER + name))
return element;
} while (namespace = namespace.namespace);
}
// search current file
if (element = this.elements.get(identifier.range.source.internalPath + PATH_DELIMITER + name)) if (element = this.elements.get(identifier.range.source.internalPath + PATH_DELIMITER + name))
return element; return element;
// search global scope
if (element = this.elements.get(name)) if (element = this.elements.get(name))
return element; return element;
this.error(DiagnosticCode.Cannot_find_name_0, identifier.range, name); this.error(DiagnosticCode.Cannot_find_name_0, identifier.range, name);
return null; return null;
} }
@ -1026,6 +1047,8 @@ export abstract class Element {
flags: ElementFlags = ElementFlags.NONE; flags: ElementFlags = ElementFlags.NONE;
/** Namespaced member elements. */ /** Namespaced member elements. */
members: Map<string,Element> | null = null; members: Map<string,Element> | null = null;
/** Parent namespace, if applicable. */
namespace: 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, internalName: string) { protected constructor(program: Program, internalName: string) {
@ -1081,6 +1104,7 @@ export abstract class Element {
/** A namespace. */ /** A namespace. */
export class Namespace extends Element { export class Namespace extends Element {
// All elements have namespace semantics. This is an explicitly declared one.
kind = ElementKind.NAMESPACE; kind = ElementKind.NAMESPACE;
/** Declaration reference. */ /** Declaration reference. */

View File

@ -6,36 +6,36 @@
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $getter-setter/Foo.get_bar (; 0 ;) (type $i) (result i32) (func $getter-setter/Foo.get:bar (; 0 ;) (type $i) (result i32)
(get_global $getter-setter/Foo._bar) (get_global $getter-setter/Foo._bar)
) )
(func $getter-setter/Foo.set_bar (; 1 ;) (type $iv) (param $0 i32) (func $getter-setter/Foo.set:bar (; 1 ;) (type $iv) (param $0 i32)
(set_global $getter-setter/Foo._bar (set_global $getter-setter/Foo._bar
(get_local $0) (get_local $0)
) )
) )
(func $start (; 2 ;) (type $v) (func $start (; 2 ;) (type $v)
(if (if
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
(unreachable) (unreachable)
) )
(call $getter-setter/Foo.set_bar (call $getter-setter/Foo.set:bar
(i32.const 1) (i32.const 1)
) )
(if (if
(i32.ne (i32.ne
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
(i32.const 1) (i32.const 1)
) )
(unreachable) (unreachable)
) )
(if (if
(block (result i32) (block (result i32)
(call $getter-setter/Foo.set_bar (call $getter-setter/Foo.set:bar
(i32.const 2) (i32.const 2)
) )
(i32.ne (i32.ne
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
(i32.const 2) (i32.const 2)
) )
) )

View File

@ -7,12 +7,12 @@
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $getter-setter/Foo.get_bar (; 0 ;) (type $i) (result i32) (func $getter-setter/Foo.get:bar (; 0 ;) (type $i) (result i32)
(return (return
(get_global $getter-setter/Foo._bar) (get_global $getter-setter/Foo._bar)
) )
) )
(func $getter-setter/Foo.set_bar (; 1 ;) (type $iv) (param $0 i32) (func $getter-setter/Foo.set:bar (; 1 ;) (type $iv) (param $0 i32)
(set_global $getter-setter/Foo._bar (set_global $getter-setter/Foo._bar
(get_local $0) (get_local $0)
) )
@ -21,19 +21,19 @@
(if (if
(i32.eqz (i32.eqz
(i32.eq (i32.eq
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
(i32.const 0) (i32.const 0)
) )
) )
(unreachable) (unreachable)
) )
(call $getter-setter/Foo.set_bar (call $getter-setter/Foo.set:bar
(i32.const 1) (i32.const 1)
) )
(if (if
(i32.eqz (i32.eqz
(i32.eq (i32.eq
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
(i32.const 1) (i32.const 1)
) )
) )
@ -43,10 +43,10 @@
(i32.eqz (i32.eqz
(i32.eq (i32.eq
(block (result i32) (block (result i32)
(call $getter-setter/Foo.set_bar (call $getter-setter/Foo.set:bar
(i32.const 2) (i32.const 2)
) )
(call $getter-setter/Foo.get_bar) (call $getter-setter/Foo.get:bar)
) )
(i32.const 2) (i32.const 2)
) )

View File

@ -1,11 +1,17 @@
(module (module
(type $i (func (result i32)))
(type $v (func)) (type $v (func))
(global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0))
(memory $0 1) (memory $0 1)
(export "test" (func $namespace/test))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $namespace/test (; 0 ;) (type $v) (start $start)
(block $__inlined_func$namespace/Outer.Inner.aFunc (func $start (; 0 ;) (type $v)
(nop) (drop
(block (result i32)
(block $__inlined_func$namespace/Outer.Inner.aFunc (result i32)
(get_global $namespace/Outer.Inner.aVar)
)
)
) )
) )
) )

View File

@ -1,12 +1,16 @@
(module (module
(type $i (func (result i32)))
(type $v (func)) (type $v (func))
(global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0))
(memory $0 1) (memory $0 1)
(export "test" (func $namespace/test))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $namespace/Outer.Inner.aFunc (; 0 ;) (type $v) (start $start)
(nop) (func $namespace/Outer.Inner.aFunc (; 0 ;) (type $i) (result i32)
(get_global $namespace/Outer.Inner.aVar)
) )
(func $namespace/test (; 1 ;) (type $v) (func $start (; 1 ;) (type $v)
(call $namespace/Outer.Inner.aFunc) (drop
(call $namespace/Outer.Inner.aFunc)
)
) )
) )

View File

@ -1,13 +1,11 @@
namespace Outer { namespace Outer {
export namespace Inner { export namespace Inner {
export let aVar: i32; export let aVar: i32 = 0;
export function aFunc(): void {} export function aFunc(): i32 { return aVar; }
export enum anEnum { ONE = 1, TWO = 2 } export enum anEnum { ONE = 1, TWO = 2 }
} }
} }
export function test(): void { Outer.Inner.aVar;
Outer.Inner.aVar; Outer.Inner.aFunc();
Outer.Inner.aFunc(); Outer.Inner.anEnum.ONE;
Outer.Inner.anEnum.ONE;
}

View File

@ -1,19 +1,25 @@
(module (module
(type $i (func (result i32)))
(type $v (func)) (type $v (func))
(global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0)) (global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0))
(global $namespace/Outer.Inner.anEnum.ONE i32 (i32.const 1)) (global $namespace/Outer.Inner.anEnum.ONE i32 (i32.const 1))
(global $namespace/Outer.Inner.anEnum.TWO i32 (i32.const 2)) (global $namespace/Outer.Inner.anEnum.TWO i32 (i32.const 2))
(global $HEAP_BASE i32 (i32.const 4)) (global $HEAP_BASE i32 (i32.const 4))
(memory $0 1) (memory $0 1)
(export "test" (func $namespace/test))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $namespace/Outer.Inner.aFunc (; 0 ;) (type $v) (start $start)
(func $namespace/Outer.Inner.aFunc (; 0 ;) (type $i) (result i32)
(return
(get_global $namespace/Outer.Inner.aVar)
)
) )
(func $namespace/test (; 1 ;) (type $v) (func $start (; 1 ;) (type $v)
(drop (drop
(get_global $namespace/Outer.Inner.aVar) (get_global $namespace/Outer.Inner.aVar)
) )
(call $namespace/Outer.Inner.aFunc) (drop
(call $namespace/Outer.Inner.aFunc)
)
(drop (drop
(get_global $namespace/Outer.Inner.anEnum.ONE) (get_global $namespace/Outer.Inner.anEnum.ONE)
) )
@ -70,7 +76,6 @@
GLOBAL: namespace/Outer.Inner.aVar GLOBAL: namespace/Outer.Inner.aVar
FUNCTION_PROTOTYPE: namespace/Outer.Inner.aFunc FUNCTION_PROTOTYPE: namespace/Outer.Inner.aFunc
ENUM: namespace/Outer.Inner.anEnum ENUM: namespace/Outer.Inner.anEnum
FUNCTION_PROTOTYPE: namespace/test
[program.exports] [program.exports]
FUNCTION_PROTOTYPE: namespace/test
;) ;)