diff --git a/src/builtins.ts b/src/builtins.ts index b84597be..2e26046c 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -54,6 +54,10 @@ export function initialize(program: Program): void { addFunction(program, "assert"); // conversions and limits + let i32Func: FunctionPrototype, + u32Func: FunctionPrototype, + i64Func: FunctionPrototype, + u64Func: FunctionPrototype; addFunction(program, "i8").members = new Map([ [ "MIN_VALUE", new Global(program, "i8.MIN_VALUE", null, Type.i8).withConstantIntegerValue(-128, -1) ], [ "MAX_VALUE", new Global(program, "i8.MAX_VALUE", null, Type.i8).withConstantIntegerValue(127, 0) ] @@ -62,11 +66,11 @@ export function initialize(program: Program): void { [ "MIN_VALUE", new Global(program, "i16.MIN_VALUE", null, Type.i16).withConstantIntegerValue(-32768, -1) ], [ "MAX_VALUE", new Global(program, "i16.MAX_VALUE", null, Type.i16).withConstantIntegerValue(32767, 0) ] ]); - addFunction(program, "i32").members = new Map([ + (i32Func = addFunction(program, "i32")).members = new Map([ [ "MIN_VALUE", new Global(program, "i32.MIN_VALUE", null, Type.i32).withConstantIntegerValue(-2147483648, -1) ], [ "MAX_VALUE", new Global(program, "i32.MAX_VALUE", null, Type.i32).withConstantIntegerValue(2147483647, 0) ] ]); - addFunction(program, "i64").members = new Map([ + (i64Func = addFunction(program, "i64")).members = new Map([ [ "MIN_VALUE", new Global(program, "i64.MIN_VALUE", null, Type.i64).withConstantIntegerValue(0, -2147483648) ], [ "MAX_VALUE", new Global(program, "i64.MAX_VALUE", null, Type.i64).withConstantIntegerValue(-1, 2147483647) ] ]); @@ -78,11 +82,11 @@ export function initialize(program: Program): void { [ "MIN_VALUE", new Global(program, "u16.MIN_VALUE", null, Type.u16).withConstantIntegerValue(0, 0) ], [ "MAX_VALUE", new Global(program, "u16.MAX_VALUE", null, Type.u16).withConstantIntegerValue(65535, 0) ] ]); - addFunction(program, "u32").members = new Map([ + (u32Func = addFunction(program, "u32")).members = new Map([ [ "MIN_VALUE", new Global(program, "u32.MIN_VALUE", null, Type.u32).withConstantIntegerValue(0, 0) ], [ "MAX_VALUE", new Global(program, "u32.MAX_VALUE", null, Type.u32).withConstantIntegerValue(-1, 0) ] ]); - addFunction(program, "u64").members = new Map([ + (u64Func = addFunction(program, "u64")).members = new Map([ [ "MIN_VALUE", new Global(program, "u64.MIN_VALUE", null, Type.u64).withConstantIntegerValue(0, 0) ], [ "MAX_VALUE", new Global(program, "u64.MAX_VALUE", null, Type.i64).withConstantIntegerValue(-1, -1) ] ]); @@ -99,12 +103,12 @@ export function initialize(program: Program): void { [ "MAX_SAFE_INTEGER", new Global(program, "f64.MAX_SAFE_INTEGER", null, Type.f64).withConstantFloatValue(9007199254740991) ] ]); if (program.target == Target.WASM64) { - program.elements.set("isize", program.elements.get("i64")); - program.elements.set("usize", program.elements.get("u64")); + program.elements.set("isize", i64Func); + program.elements.set("usize", u64Func); addConstant(program, "HEAP_BASE", Type.usize64); } else { - program.elements.set("isize", program.elements.get("i32")); - program.elements.set("usize", program.elements.get("u32")); + program.elements.set("isize", i32Func); + program.elements.set("usize", u32Func); addConstant(program, "HEAP_BASE", Type.usize32); } } diff --git a/src/compiler.ts b/src/compiler.ts index aa7b3221..74c723d3 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -769,12 +769,18 @@ export class Compiler extends DiagnosticEmitter { case NodeKind.TRY: return this.compileTryStatement(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: return this.compileVariableStatement(statement); case NodeKind.WHILE: return this.compileWhileStatement(statement); } + this.error(DiagnosticCode.Operation_not_supported, statement.range); throw new Error("unexpected statement kind"); } diff --git a/src/program.ts b/src/program.ts index e15a6e9d..80d25e52 100644 --- a/src/program.ts +++ b/src/program.ts @@ -76,6 +76,8 @@ export class Program extends DiagnosticEmitter { elements: Map = new Map(); /** Types by internal name. */ types: Map = noTypesYet; + /** Declared type aliases. */ + typeAliases: Map = new Map(); /** Exports of individual files by internal name. Not global exports. */ exports: Map = new Map(); @@ -663,12 +665,11 @@ export class Program extends DiagnosticEmitter { private initializeType(declaration: TypeDeclaration, namespace: Element | null = null): void { // type aliases are program globals const name: string = declaration.name.name; - if (this.types.has(name)) { + if (this.types.has(name) || this.typeAliases.has(name)) { this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); return; } - // TODO: queue, then resolve - throw new Error("not implemented"); + this.typeAliases.set(name, declaration.alias); } private initializeVariables(statement: VariableStatement, namespace: Element | null = null): void { @@ -741,6 +742,11 @@ export class Program extends DiagnosticEmitter { if (type = this.types.get(globalName)) return type; + // check type alias + let alias: TypeNode | null = this.typeAliases.get(globalName); + if (alias && (type = this.resolveType(alias, null, reportNotFound))) + return type; + if (reportNotFound) this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName); diff --git a/tests/compiler/typealias.optimized.wast b/tests/compiler/typealias.optimized.wast new file mode 100644 index 00000000..c93932cd --- /dev/null +++ b/tests/compiler/typealias.optimized.wast @@ -0,0 +1,14 @@ +(module + (type $ii (func (param i32) (result i32))) + (type $v (func)) + (memory $0 1) + (export "alias" (func $typealias/alias)) + (export "memory" (memory $0)) + (start $start) + (func $typealias/alias (; 0 ;) (type $ii) (param $0 i32) (result i32) + (get_local $0) + ) + (func $start (; 1 ;) (type $v) + (nop) + ) +) diff --git a/tests/compiler/typealias.ts b/tests/compiler/typealias.ts new file mode 100644 index 00000000..2d9ded09 --- /dev/null +++ b/tests/compiler/typealias.ts @@ -0,0 +1,5 @@ +type alias = i32; + +export function alias(a: alias): alias { + return a; +} diff --git a/tests/compiler/typealias.wast b/tests/compiler/typealias.wast new file mode 100644 index 00000000..55e4cc9e --- /dev/null +++ b/tests/compiler/typealias.wast @@ -0,0 +1,67 @@ +(module + (type $ii (func (param i32) (result i32))) + (type $v (func)) + (global $HEAP_BASE i32 (i32.const 4)) + (memory $0 1) + (export "alias" (func $typealias/alias)) + (export "memory" (memory $0)) + (start $start) + (func $typealias/alias (; 0 ;) (type $ii) (param $0 i32) (result i32) + (return + (get_local $0) + ) + ) + (func $start (; 1 ;) (type $v) + (nop) + ) +) +(; +[program.elements] + NaN + Infinity + isNaN + isFinite + clz + ctz + popcnt + rotl + rotr + abs + max + min + ceil + floor + copysign + nearest + reinterpret + sqrt + trunc + load + store + sizeof + select + unreachable + current_memory + grow_memory + parseInt + parseFloat + changetype + assert + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize + HEAP_BASE + typealias/alias +[program.exports] + typealias/alias +;)