From 7cf879fb4bba9d330f81ac73abdf126560ae648b Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Fri, 15 Dec 2017 15:00:19 +0100 Subject: [PATCH] Type limits --- README.md | 15 +-- src/builtins.ts | 59 +++++++++- src/compiler.ts | 73 ++++++++----- src/decompiler.ts | 1 - src/program.ts | 148 +++++++++++++++++-------- std/assembly.d.ts | 79 ++++++++++++++ std/portable.d.ts | 75 ++++++++++++- std/portable.js | 55 ++++++++++ std/tsconfig.json | 3 + tests/compiler/assert.wast | 13 +++ tests/compiler/binary.wast | 13 +++ tests/compiler/builtins.wast | 13 +++ tests/compiler/class.wast | 13 +++ tests/compiler/declare.wast | 13 +++ tests/compiler/do.wast | 13 +++ tests/compiler/enum.wast | 13 +++ tests/compiler/export.wast | 13 +++ tests/compiler/for.wast | 13 +++ tests/compiler/game-of-life.wast | 13 +++ tests/compiler/i64.wast | 13 +++ tests/compiler/if.wast | 13 +++ tests/compiler/import.wast | 13 +++ tests/compiler/limits.optimized.wast | 9 ++ tests/compiler/limits.ts | 26 +++++ tests/compiler/limits.wast | 155 +++++++++++++++++++++++++++ tests/compiler/literals.wast | 13 +++ tests/compiler/logical.wast | 13 +++ tests/compiler/memcpy.wast | 13 +++ tests/compiler/namespace.wast | 13 +++ tests/compiler/reexport.wast | 13 +++ tests/compiler/switch.wast | 13 +++ tests/compiler/ternary.wast | 13 +++ tests/compiler/tlsf.wast | 13 +++ tests/compiler/unary.wast | 13 +++ tests/compiler/while.wast | 13 +++ 35 files changed, 911 insertions(+), 86 deletions(-) create mode 100644 std/tsconfig.json create mode 100644 tests/compiler/limits.optimized.wast create mode 100644 tests/compiler/limits.ts create mode 100644 tests/compiler/limits.wast diff --git a/README.md b/README.md index d58da761..3add3056 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ -AssemblyScript NEXT -=================== +![](https://s.gravatar.com/avatar/f105de3decfafc734b8eabe9a960b25d?size=64) AssemblyScript NEXT +================= -[![Build Status](https://travis-ci.org/AssemblyScript/next.svg?branch=master)](https://travis-ci.org/AssemblyScript/next) +[![Build Status](https://travis-ci.org/AssemblyScript/assemblyscript.svg?branch=master)](https://travis-ci.org/AssemblyScript/assemblyscript) **AssemblyScript** is a new compiler targeting [WebAssembly](http://webassembly.org) while utilizing [TypeScript](http://www.typescriptlang.org)'s syntax and [node](https://nodejs.org)'s vibrant ecosystem. Instead of requiring complex toolchains to set up, you can simply `npm install` it - or run it in a browser. -By compiling syntactially (not necessarily semantically) valid TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR, the resulting module can be validated, optimized, emitted in WebAssembly text or binary format and converted to [asm.js](http://asmjs.org) as a polyfill. - Note, though, that this version of the compiler (0.5.0, NEXT) is relatively new and does not yet support some features a TypeScript programmer might expect, e.g., strings, arrays and classes. See [the AssemblyScript wiki](https://github.com/AssemblyScript/assemblyscript/wiki) for additional information and documentation. +How does it work? +----------------- + +By compiling syntactially (not necessarily semantically) valid TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR, the resulting module can be validated, optimized, emitted in WebAssembly text or binary format and converted to [asm.js](http://asmjs.org) as a polyfill. + Examples -------- @@ -22,7 +25,7 @@ A few early examples to get an idea: Getting started --------------- -If you'd like to try it today or even plan to contribute, this is how you do it: +This version of the compiler is not on [npm](https://www.npmjs.com/package/assemblyscript), yet, but if you'd like to try it today or even plan to contribute, this is how you do it: ``` $> git clone https://github.com/AssemblyScript/next.git diff --git a/src/builtins.ts b/src/builtins.ts index d13fd244..185ea53c 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -3,7 +3,7 @@ import { DiagnosticCode } from "./diagnostics"; import { Node, Expression } from "./ast"; import { Type } from "./types"; import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module"; -import { Program, ElementFlags, FunctionPrototype, Local } from "./program"; +import { Program, ElementFlags, Element, Global, FunctionPrototype, Local } from "./program"; /** Initializes the specified program with built-in functions. */ export function initialize(program: Program): void { @@ -35,14 +35,67 @@ export function initialize(program: Program): void { addFunction(program, "assert"); addFunction(program, "parseInt"); addFunction(program, "parseFloat"); + + 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) ] + ]); + addFunction(program, "i16").members = new Map([ + [ "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([ + [ "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([ + [ "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) ] + ]); + addFunction(program, "u8").members = new Map([ + [ "MIN_VALUE", new Global(program, "u8.MIN_VALUE", null, Type.u8).withConstantIntegerValue(0, 0) ], + [ "MAX_VALUE", new Global(program, "u8.MAX_VALUE", null, Type.u8).withConstantIntegerValue(255, 0) ] + ]); + addFunction(program, "u16").members = new Map([ + [ "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([ + [ "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([ + [ "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) ] + ]); + addFunction(program, "bool").members = new Map([ + [ "MIN_VALUE", new Global(program, "bool.MIN_VALUE", null, Type.bool).withConstantIntegerValue(0, 0) ], + [ "MAX_VALUE", new Global(program, "bool.MAX_VALUE", null, Type.bool).withConstantIntegerValue(1, 0) ] + ]); + addFunction(program, "f32").members = new Map([ + [ "MIN_SAFE_INTEGER", new Global(program, "f32.MIN_SAFE_INTEGER", null, Type.f32).withConstantFloatValue(-16777215) ], + [ "MAX_SAFE_INTEGER", new Global(program, "f32.MAX_SAFE_INTEGER", null, Type.f32).withConstantFloatValue(16777215) ] + ]); + addFunction(program, "f64").members = new Map([ + [ "MIN_SAFE_INTEGER", new Global(program, "f64.MIN_SAFE_INTEGER", null, Type.f64).withConstantFloatValue(-9007199254740991) ], + [ "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")); + } else { + program.elements.set("isize", program.elements.get("i32")); + program.elements.set("usize", program.elements.get("u32")); + } } /** Adds a built-in function to the specified program. */ -function addFunction(program: Program, name: string, isGeneric: bool = false): void { - let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null); +function addFunction(program: Program, name: string, isGeneric: bool = false): FunctionPrototype { + let prototype: FunctionPrototype = new FunctionPrototype(program, name, name, null, null); prototype.isBuiltIn = true; if (isGeneric) prototype.isGeneric = true; program.elements.set(name, prototype); + return prototype; } /** Compiles a call to a built-in function. */ diff --git a/src/compiler.ts b/src/compiler.ts index a3cf552a..22857574 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -93,7 +93,8 @@ import { UnaryPrefixExpression, // utility - hasModifier + hasModifier, + InterfaceDeclaration } from "./ast"; import { @@ -179,7 +180,7 @@ export class Compiler extends DiagnosticEmitter { this.program = program; this.options = options ? options : new Options(); this.module = this.options.noEmit ? Module.createStub() : Module.create(); - const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null); + const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", "start", null); const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null); this.currentFunction = this.startFunction = startFunctionInstance; this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null` @@ -544,6 +545,7 @@ export class Compiler extends DiagnosticEmitter { } else { this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, stmts, NativeType.None)); } + instance.finalize(); return true; } @@ -561,6 +563,11 @@ export class Compiler extends DiagnosticEmitter { this.compileClassDeclaration(member, []); break; + case NodeKind.INTERFACE: + if ((noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) && !(member).typeParameters.length) + this.compileInterfaceDeclaration(member, []); + break; + case NodeKind.ENUM: if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (member).modifiers)) this.compileEnumDeclaration(member); @@ -684,6 +691,10 @@ export class Compiler extends DiagnosticEmitter { throw new Error("not implemented"); } + compileInterfaceDeclaration(declaration: InterfaceDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map | null = null, alternativeReportNode: Node | null = null): void { + throw new Error("not implemented"); + } + // memory /** Adds a static memory segment with the specified data. */ @@ -1896,30 +1907,6 @@ export class Compiler extends DiagnosticEmitter { let expr: ExpressionRef; switch (target.kind) { - case ElementKind.ENUM: - case ElementKind.CLASS_PROTOTYPE: - case ElementKind.CLASS: - case ElementKind.NAMESPACE: - if (target.members) { - element = target.members.get(propertyName); - if (!element) { - this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName); - return this.module.createUnreachable(); - } - - // handle enum values right away - if (element.kind == ElementKind.ENUMVALUE) { - this.currentType = Type.i32; - return (element).hasConstantValue - ? this.module.createI32((element).constantValue) - : this.module.createGetGlobal((element).internalName, NativeType.I32); - } - } else { - this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName); - return this.module.createUnreachable(); - } - break; - case ElementKind.LOCAL: element = (target).type.classType; if (!element) { @@ -1941,7 +1928,25 @@ export class Compiler extends DiagnosticEmitter { break; default: - throw new Error("unexpected target kind"); + if (target.members) { + element = target.members.get(propertyName); + if (!element) { + this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName); + return this.module.createUnreachable(); + } + + // handle enum values right away + if (element.kind == ElementKind.ENUMVALUE) { + this.currentType = Type.i32; + return (element).hasConstantValue + ? this.module.createI32((element).constantValue) + : this.module.createGetGlobal((element).internalName, NativeType.I32); + } + } else { + this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName); + return this.module.createUnreachable(); + } + break; } // handle the element @@ -1951,8 +1956,18 @@ export class Compiler extends DiagnosticEmitter { return this.module.createGetLocal((element).index, typeToNativeType(this.currentType = (element).type)); case ElementKind.GLOBAL: - this.compileGlobal(element); - return this.module.createGetGlobal((element).internalName, typeToNativeType(this.currentType = (element).type)); + if (!this.compileGlobal(element)) + return this.module.createUnreachable(); + this.currentType = (element).type; + if ((element).hasConstantValue) + return this.currentType== Type.f32 + ? this.module.createF32((element).constantFloatValue) + : this.currentType == Type.f64 + ? this.module.createF64((element).constantFloatValue) + : this.currentType.isLongInteger + ? this.module.createI64(((element).constantIntegerValue).lo, ((element).constantIntegerValue).hi) + : this.module.createI32(((element).constantIntegerValue).lo); + return this.module.createGetGlobal((element).internalName, typeToNativeType(this.currentType)); case ElementKind.FUNCTION: // getter if (!(element).prototype.isGetter) { diff --git a/src/decompiler.ts b/src/decompiler.ts index 5f654009..64d0b228 100644 --- a/src/decompiler.ts +++ b/src/decompiler.ts @@ -47,7 +47,6 @@ export class Decompiler { this.push("("); let k: Index = _BinaryenFunctionGetNumParams(func); for (let i: Index = 0; i < k; ++i) { - console.log("rat"); if (i > 0) this.push(", "); this.push("$"); diff --git a/src/program.ts b/src/program.ts index d207bfc6..9f5b2e8c 100644 --- a/src/program.ts +++ b/src/program.ts @@ -216,7 +216,7 @@ export class Program extends DiagnosticEmitter { this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); return; } - const prototype: ClassPrototype = new ClassPrototype(this, internalName, declaration); + const prototype: ClassPrototype = new ClassPrototype(this, declaration.identifier.name, internalName, declaration); this.elements.set(internalName, prototype); if (namespace) { @@ -306,7 +306,7 @@ export class Program extends DiagnosticEmitter { } } else classPrototype.members = new Map(); - const staticPrototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, null); + const staticPrototype: FunctionPrototype = new FunctionPrototype(this, name, internalName, declaration, null); classPrototype.members.set(name, staticPrototype); this.elements.set(internalName, staticPrototype); @@ -319,7 +319,7 @@ export class Program extends DiagnosticEmitter { } } else classPrototype.instanceMembers = new Map(); - const instancePrototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, classPrototype); + const instancePrototype: FunctionPrototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype); classPrototype.instanceMembers.set(name, instancePrototype); } } @@ -455,7 +455,7 @@ export class Program extends DiagnosticEmitter { this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); return; } - const prototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, null); + const prototype: FunctionPrototype = new FunctionPrototype(this, declaration.identifier.name, internalName, declaration, null); this.elements.set(internalName, prototype); if (namespace) { @@ -531,7 +531,7 @@ export class Program extends DiagnosticEmitter { private initializeInterface(declaration: InterfaceDeclaration, namespace: Element | null = null): void { const internalName: string = declaration.internalName; - const prototype: InterfacePrototype = new InterfacePrototype(this, internalName, declaration); + const prototype: InterfacePrototype = new InterfacePrototype(this, declaration.identifier.name, internalName, declaration); if (this.elements.has(internalName)) { this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); @@ -1024,6 +1024,18 @@ export class Global extends Element { } this.type = type; // resolved later if `null` } + + withConstantIntegerValue(lo: i32, hi: i32): this { + this.constantIntegerValue = new I64(lo, hi); + this.hasConstantValue = true; + return this; + } + + withConstantFloatValue(value: f64): this { + this.constantFloatValue = value; + this.hasConstantValue = true; + return this; + } } /** A function parameter. */ @@ -1070,14 +1082,17 @@ export class FunctionPrototype extends Element { /** Declaration reference. */ declaration: FunctionDeclaration | null; - /** Class prototype reference. */ + /** If an instance method, the class prototype reference. */ classPrototype: ClassPrototype | null; /** Resolved instances. */ instances: Map = new Map(); + /** Simple name. */ + simpleName: string; /** Constructs a new function prototype. */ - constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) { + constructor(program: Program, simpleName: string, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) { super(program, internalName); + this.simpleName = simpleName; if (this.declaration = declaration) { if (this.declaration.modifiers) for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) { @@ -1142,7 +1157,7 @@ export class FunctionPrototype extends Element { } else return null; } else - return null; // TODO: infer type? (currently reported by parser) + return null; } // resolve return type @@ -1155,7 +1170,7 @@ export class FunctionPrototype extends Element { else return null; } else - return null; // TODO: infer type? (currently reported by parser) + return null; let internalName: string = this.internalName; if (instanceKey.length) @@ -1168,17 +1183,20 @@ export class FunctionPrototype extends Element { resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map | null, alternativeReportNode: Node | null): Function | null { let resolvedTypeArguments: Type[] | null; if (this.isGeneric) { + assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); if (!this.declaration) throw new Error("missing declaration"); resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode); if (!resolvedTypeArguments) return null; } else { - // TODO: check typeArgumentNodes being empty + assert(typeArgumentNodes == null || typeArgumentNodes.length == 0); resolvedTypeArguments = []; } return this.resolve(resolvedTypeArguments, contextualTypeArguments); } + + toString(): string { return this.simpleName; } } /** A resolved function. */ @@ -1194,7 +1212,7 @@ export class Function extends Element { parameters: Parameter[]; /** Concrete return type. */ returnType: Type; - /** If a method, the concrete class it is a member of. */ + /** If an instance method, the concrete class it is a member of. */ instanceMethodOf: Class | null; /** Map of locals by name. */ locals: Map = new Map(); @@ -1203,7 +1221,7 @@ export class Function extends Element { /** Current break context label. */ breakContext: string | null = null; /** Contextual type arguments. */ - contextualTypeArguments: Map = new Map(); + contextualTypeArguments: Map | null; private nextBreakId: i32 = 0; private breakStack: i32[] | null = null; @@ -1219,19 +1237,21 @@ export class Function extends Element { this.flags = prototype.flags; let localIndex: i32 = 0; if (instanceMethodOf) { + assert(this.isInstance); this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type)); - for (let [name, type] of instanceMethodOf.contextualTypeArguments) - this.contextualTypeArguments.set(name, type); - } + if (instanceMethodOf.contextualTypeArguments) { + if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map(); + for (let [name, type] of instanceMethodOf.contextualTypeArguments) + this.contextualTypeArguments.set(name, type); + } + } else + assert(!this.isInstance); for (let i: i32 = 0, k: i32 = parameters.length; i < k; ++i) { const parameter: Parameter = parameters[i]; this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type)); } } - /** Tests if this function is an instance method. */ - get isInstance(): bool { return this.instanceMethodOf != null; } - /** Adds a local of the specified type, with an optional name. */ addLocal(type: Type, name: string | null = null): Local { // if it has a name, check previously as this method will throw otherwise @@ -1320,6 +1340,16 @@ export class Function extends Element { this.breakStack = null; } } + + /** Finalizes the function once compiled, releasing no longer needed resources. */ + finalize(): void { + assert(!this.breakStack || !this.breakStack.length, "break stack is not empty"); + this.breakStack = null; + this.breakContext = null; + this.tempI32s = this.tempI64s = this.tempF32s = this.tempF64s = null; + } + + toString(): string { return this.prototype.simpleName; } } /** A yet unresolved instance field prototype. */ @@ -1380,9 +1410,12 @@ export class ClassPrototype extends Element { instances: Map = new Map(); /** Instance member prototypes. */ instanceMembers: Map | null = null; + /** Simple name. */ + simpleName: string; - constructor(program: Program, internalName: string, declaration: ClassDeclaration | null = null) { + constructor(program: Program, simpleName: string, internalName: string, declaration: ClassDeclaration | null = null) { super(program, internalName); + this.simpleName = simpleName; if (this.declaration = declaration) { if (this.declaration.modifiers) { for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) { @@ -1400,29 +1433,62 @@ export class ClassPrototype extends Element { } resolve(typeArguments: Type[], contextualTypeArguments: Map | null): Class { - const key: string = typesToString(typeArguments, "", ""); - let instance: Class | null = this.instances.get(key); + const instanceKey: string = typesToString(typeArguments, "", ""); + let instance: Class | null = this.instances.get(instanceKey); if (instance) return instance; - if (!this.declaration) + const declaration: ClassDeclaration | null = this.declaration; + if (!declaration) throw new Error("unexpected instantiation of internal class"); - throw new Error("not implemented"); + + // override call specific contextual type arguments + let i: i32, k: i32 = typeArguments.length; + if (k) { + const inheritedTypeArguments: Map | null = contextualTypeArguments; + contextualTypeArguments = new Map(); + if (inheritedTypeArguments) + for (let [name, type] of inheritedTypeArguments) + contextualTypeArguments.set(name, type); + for (i = 0; i < k; ++i) + contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]); + } + + // TODO: set up instance fields and methods + if (this.instanceMembers) + for (let [key, member] of this.instanceMembers) { + switch (member.kind) { + case ElementKind.FIELD_PROTOTYPE: break; + case ElementKind.FUNCTION_PROTOTYPE: break; + default: throw new Error("unexpected instance member"); + } + } + + let internalName: string = this.internalName; + if (instanceKey.length) + internalName += "<" + instanceKey + ">"; + instance = new Class(this, internalName, typeArguments, null); // TODO: base class + instance.contextualTypeArguments = contextualTypeArguments; + this.instances.set(instanceKey, instance); + return instance; } resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map | null, alternativeReportNode: Node | null): Class | null { let resolvedTypeArguments: Type[] | null; if (this.isGeneric) { + assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); if (!this.declaration) - throw new Error("not implemented"); // generic built-in + throw new Error("missing declaration"); // generic built-in resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode); if (!resolvedTypeArguments) return null; } else { - // TODO: check typeArgumentNodes being empty + assert(typeArgumentNodes == null || !typeArgumentNodes.length); resolvedTypeArguments = []; } return this.resolve(resolvedTypeArguments, contextualTypeArguments); } + + toString(): string { return this.simpleName; } } /** A resolved class. */ @@ -1438,16 +1504,8 @@ export class Class extends Element { type: Type; /** Base class, if applicable. */ base: Class | null; - /** Contextual type argumentsfor fields and methods. */ - contextualTypeArguments: Map = new Map(); - /** Instance fields. */ - instanceFields: Map | null = null; - /** Instance methods. */ - instanceMethods: Map | null = null; - /** Instance getters. */ - instanceGetters: Map | null = null; - /** Instance setters. */ - instanceSetters: Map | null = null; + /** Contextual type arguments for fields and methods. */ + contextualTypeArguments: Map | null = null; /** Constructs a new class. */ constructor(prototype: ClassPrototype, internalName: string, typeArguments: Type[] = [], base: Class | null = null) { @@ -1459,9 +1517,11 @@ export class Class extends Element { this.base = base; // inherit contextual type arguments from base class - if (base) + if (base && base.contextualTypeArguments) { + if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map(); for (let [name, type] of base.contextualTypeArguments) this.contextualTypeArguments.set(name, type); + } // apply instance-specific contextual type arguments const declaration: ClassDeclaration | null = this.prototype.declaration; @@ -1469,14 +1529,16 @@ export class Class extends Element { const typeParameters: TypeParameter[] = declaration.typeParameters; if (typeParameters.length != typeArguments.length) throw new Error("unexpected type argument count mismatch"); - for (let i: i32 = 0, k: i32 = typeArguments.length; i < k; ++i) - this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]); + const k: i32 = typeArguments.length; + if (k) { + if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map(); + for (let i: i32 = 0; i < k; ++i) + this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]); + } } } - toString(): string { - throw new Error("not implemented"); - } + toString(): string { return this.prototype.simpleName; } } /** A yet unresolved interface. */ @@ -1488,8 +1550,8 @@ export class InterfacePrototype extends ClassPrototype { declaration: InterfaceDeclaration | null; // more specific /** Constructs a new interface prototype. */ - constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null = null) { - super(program, internalName, declaration); + constructor(program: Program, simpleName: string, internalName: string, declaration: InterfaceDeclaration | null = null) { + super(program, simpleName, internalName, declaration); } } diff --git a/std/assembly.d.ts b/std/assembly.d.ts index bfbeba9b..4096cbf5 100644 --- a/std/assembly.d.ts +++ b/std/assembly.d.ts @@ -29,6 +29,85 @@ declare type f32 = number; /** A 64-bit float. */ declare type f64 = number; +/** Converts any other numeric value to an 8-bit signed integer. */ +declare function i8(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; +declare namespace i8 { + export const MIN_VALUE: i8; + export const MAX_VALUE: i8; +} +/** Converts any other numeric value to a 16-bit signed integer. */ +declare function i16(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; +declare namespace i16 { + export const MIN_VALUE: i16; + export const MAX_VALUE: i16; +} +/** Converts any other numeric value to a 32-bit signed integer. */ +declare function i32(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i32; +declare namespace i32 { + export const MIN_VALUE: i32; + export const MAX_VALUE: i32; +} +/** Converts any other numeric value to a 64-bit signed integer. */ +declare function i64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i64; +declare namespace i64 { + export const MIN_VALUE: i64; + export const MAX_VALUE: i64; +} +/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) signed integer. */ +declare function isize(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): isize; +declare namespace isize { + export const MIN_VALUE: isize; + export const MAX_VALUE: isize; +} +/** Converts any other numeric value to an 8-bit unsigned integer. */ +declare function u8(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; +declare namespace u8 { + export const MIN_VALUE: u8; + export const MAX_VALUE: u8; +} +/** Converts any other numeric value to a 16-bit unsigned integer. */ +declare function u16(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; +declare namespace u16 { + export const MIN_VALUE: u16; + export const MAX_VALUE: u16; +} +/** Converts any other numeric value to a 32-bit unsigned integer. */ +declare function u32(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i32; +declare namespace u32 { + export const MIN_VALUE: u32; + export const MAX_VALUE: u32; +} +/** Converts any other numeric value to a 64-bit unsigned integer. */ +declare function u64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i64; +declare namespace u64 { + export const MIN_VALUE: u64; + export const MAX_VALUE: u64; +} +/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) unsigned integer. */ +declare function usize(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): isize; +declare namespace usize { + export const MIN_VALUE: usize; + export const MAX_VALUE: usize; +} +/** Converts any other numeric value to a 1-bit unsigned integer. */ +declare function bool(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): bool; +declare namespace bool { + export const MIN_VALUE: bool; + export const MAX_VALUE: bool; +} +/** Converts any other numeric value to a 32-bit float. */ +declare function f32(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): f32; +declare namespace f32 { + export const MIN_SAFE_INTEGER: f32; + export const MAX_SAFE_INTEGER: f32; +} +/** Converts any other numeric value to a 64-bit float. */ +declare function f64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): f64; +declare namespace f64 { + export const MIN_SAFE_INTEGER: f64; + export const MAX_SAFE_INTEGER: f64; +} + // Built-ins /** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */ diff --git a/std/portable.d.ts b/std/portable.d.ts index bb576da0..303c8ec7 100644 --- a/std/portable.d.ts +++ b/std/portable.d.ts @@ -10,16 +10,83 @@ // of 2^53-1) and instead require a compatibility layer to work in JS as well. See: src/util/i64.ts declare type i8 = number; -declare type u8 = number; declare type i16 = number; -declare type u16 = number; declare type i32 = number; -declare type u32 = number; declare type isize = number; +declare type u8 = number; +declare type u16 = number; +declare type u32 = number; +declare type bool = boolean; declare type usize = number; declare type f32 = number; declare type f64 = number; -declare type bool = boolean; + +/** Converts any other numeric value to an 8-bit signed integer. */ +declare function i8(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare namespace i8 { + export const MIN_VALUE: i8; + export const MAX_VALUE: i8; +} +/** Converts any other numeric value to a 16-bit signed integer. */ +declare function i16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare namespace i16 { + export const MIN_VALUE: i16; + export const MAX_VALUE: i16; +} +/** Converts any other numeric value to a 32-bit signed integer. */ +declare function i32(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i32; +declare namespace i32 { + export const MIN_VALUE: i32; + export const MAX_VALUE: i32; +} +/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) signed integer. */ +declare function isize(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): isize; +declare namespace isize { + export const MIN_VALUE: isize; + export const MAX_VALUE: isize; +} +/** Converts any other numeric value to an 8-bit unsigned integer. */ +declare function u8(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare namespace u8 { + export const MIN_VALUE: u8; + export const MAX_VALUE: u8; +} +/** Converts any other numeric value to a 16-bit unsigned integer. */ +declare function u16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare namespace u16 { + export const MIN_VALUE: u16; + export const MAX_VALUE: u16; +} +/** Converts any other numeric value to a 32-bit unsigned integer. */ +declare function u32(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i32; +declare namespace u32 { + export const MIN_VALUE: u32; + export const MAX_VALUE: u32; +} +/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) unsigned integer. */ +declare function usize(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): isize; +declare namespace usize { + export const MIN_VALUE: usize; + export const MAX_VALUE: usize; +} +/** Converts any other numeric value to a 1-bit unsigned integer. */ +declare function bool(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): bool; +declare namespace bool { + export const MIN_VALUE: bool; + export const MAX_VALUE: bool; +} +/** Converts any other numeric value to a 32-bit float. */ +declare function f32(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): f32; +declare namespace f32 { + export const MIN_SAFE_INTEGER: f32; + export const MAX_SAFE_INTEGER: f32; +} +/** Converts any other numeric value to a 64-bit float. */ +declare function f64(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): f64; +declare namespace f64 { + export const MIN_SAFE_INTEGER: f64; + export const MAX_SAFE_INTEGER: f64; +} // Portable built-ins diff --git a/std/portable.js b/std/portable.js index f96536ad..4a0c0c74 100644 --- a/std/portable.js +++ b/std/portable.js @@ -1,5 +1,60 @@ var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self; +Object.defineProperties( + globalScope["i8"] = function i8(value) { return value << 24 >> 24; } +, { + "MIN_VALUE": { value: -128, writable: false }, + "MAX_VALUE": { value: 127, writable: false } +}); +Object.defineProperties( + globalScope["i16"] = function i16(value) { return value << 16 >> 16; } +, { + "MIN_VALUE": { value: -32768, writable: false }, + "MAX_VALUE": { value: 32767, writable: false } +}); +Object.defineProperties( + globalScope["i32"] = globalScope["isize"] = function i32(value) { return value | 0; } +, { + "MIN_VALUE": { value: -2147483648, writable: false }, + "MAX_VALUE": { value: 2147483647, writable: false } +}); +Object.defineProperties( + globalScope["u8"] = function u8(value) { return value & 0xff; } +, { + "MIN_VALUE": { value: 0, writable: false }, + "MAX_VALUE": { value: 255, writable: false } +}); +Object.defineProperties( + globalScope["u16"] = function u16(value) { return value & 0xffff; } +, { + "MIN_VALUE": { value: 0, writable: false }, + "MAX_VALUE": { value: 65535, writable: false } +}); +Object.defineProperties( + globalScope["u32"] = globalScope["usize"] = function u32(value) { return value >>> 0; } +, { + "MIN_VALUE": { value: 0, writable: false }, + "MAX_VALUE": { value: 4294967295, writable: false } +}); +Object.defineProperties( + globalScope["bool"] = function bool(value) { return Boolean(value); } +, { + "MIN_VALUE": { value: 0, writable: false }, + "MAX_VALUE": { value: 1, writable: false } +}); +Object.defineProperties( + globalScope["f32"] = function f32(value) { return Math.fround(value); } +, { + "MIN_SAFE_INTEGER": { value: -16777215, writable: false }, + "MAX_SAFE_INTEGER": { value: 16777215, writable: false } +}); +Object.defineProperties( + globalScope["f64"] = function f64(value) { return +value; } +, { + "MIN_SAFE_INTEGER": { value: -9007199254740991, writable: false }, + "MAX_SAFE_INTEGER": { value: 9007199254740991, writable: false } +}); + globalScope["clz"] = Math.clz32; globalScope["abs"] = Math.abs; globalScope["max"] = Math.max; diff --git a/std/tsconfig.json b/std/tsconfig.json new file mode 100644 index 00000000..2daed60f --- /dev/null +++ b/std/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig-base.json" +} diff --git a/tests/compiler/assert.wast b/tests/compiler/assert.wast index 7920843f..437d7923 100644 --- a/tests/compiler/assert.wast +++ b/tests/compiler/assert.wast @@ -43,6 +43,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize [program.exports] ;) diff --git a/tests/compiler/binary.wast b/tests/compiler/binary.wast index fdc93e6b..52b2095c 100644 --- a/tests/compiler/binary.wast +++ b/tests/compiler/binary.wast @@ -846,6 +846,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize binary/b binary/i binary/I diff --git a/tests/compiler/builtins.wast b/tests/compiler/builtins.wast index c9577b99..cd9ec882 100644 --- a/tests/compiler/builtins.wast +++ b/tests/compiler/builtins.wast @@ -1063,6 +1063,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize builtins/b builtins/i builtins/I diff --git a/tests/compiler/class.wast b/tests/compiler/class.wast index f31a992e..a6d129f0 100644 --- a/tests/compiler/class.wast +++ b/tests/compiler/class.wast @@ -71,6 +71,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize class/Animal class/Animal.MAX class/Animal.add diff --git a/tests/compiler/declare.wast b/tests/compiler/declare.wast index a5532316..d3436ff7 100644 --- a/tests/compiler/declare.wast +++ b/tests/compiler/declare.wast @@ -36,6 +36,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize declare/external [program.exports] declare/external diff --git a/tests/compiler/do.wast b/tests/compiler/do.wast index f85f728d..2018fc40 100644 --- a/tests/compiler/do.wast +++ b/tests/compiler/do.wast @@ -81,6 +81,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize do/loopDo do/loopDoInDo [program.exports] diff --git a/tests/compiler/enum.wast b/tests/compiler/enum.wast index 9f571813..d8fde227 100644 --- a/tests/compiler/enum.wast +++ b/tests/compiler/enum.wast @@ -66,6 +66,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize enum/Implicit enum/Explicit enum/Mixed diff --git a/tests/compiler/export.wast b/tests/compiler/export.wast index 7873c8e4..af2ba327 100644 --- a/tests/compiler/export.wast +++ b/tests/compiler/export.wast @@ -60,6 +60,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize export/add export/sub export/a diff --git a/tests/compiler/for.wast b/tests/compiler/for.wast index bee6a79d..71c7245a 100644 --- a/tests/compiler/for.wast +++ b/tests/compiler/for.wast @@ -177,6 +177,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize for/i [program.exports] diff --git a/tests/compiler/game-of-life.wast b/tests/compiler/game-of-life.wast index 9776b8a1..28ad71df 100644 --- a/tests/compiler/game-of-life.wast +++ b/tests/compiler/game-of-life.wast @@ -338,6 +338,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize ../../examples/game-of-life/assembly/game-of-life/w ../../examples/game-of-life/assembly/game-of-life/h ../../examples/game-of-life/assembly/game-of-life/s diff --git a/tests/compiler/i64.wast b/tests/compiler/i64.wast index 0af10218..e26991b3 100644 --- a/tests/compiler/i64.wast +++ b/tests/compiler/i64.wast @@ -1219,6 +1219,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize ../../examples/i64-polyfill/assembly/i64/lo ../../examples/i64-polyfill/assembly/i64/hi ../../examples/i64-polyfill/assembly/i64/getLo diff --git a/tests/compiler/if.wast b/tests/compiler/if.wast index 01bcb40a..7971bbdc 100644 --- a/tests/compiler/if.wast +++ b/tests/compiler/if.wast @@ -76,6 +76,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize if/ifThenElse if/ifThen if/ifThenElseBlock diff --git a/tests/compiler/import.wast b/tests/compiler/import.wast index 083436e9..57f22c4f 100644 --- a/tests/compiler/import.wast +++ b/tests/compiler/import.wast @@ -71,6 +71,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize export/add export/sub export/a diff --git a/tests/compiler/limits.optimized.wast b/tests/compiler/limits.optimized.wast new file mode 100644 index 00000000..bfec40ca --- /dev/null +++ b/tests/compiler/limits.optimized.wast @@ -0,0 +1,9 @@ +(module + (type $v (func)) + (memory $0 1) + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (nop) + ) +) diff --git a/tests/compiler/limits.ts b/tests/compiler/limits.ts new file mode 100644 index 00000000..46c33ee6 --- /dev/null +++ b/tests/compiler/limits.ts @@ -0,0 +1,26 @@ +i8.MIN_VALUE; +i8.MAX_VALUE; +i16.MIN_VALUE; +i16.MAX_VALUE; +i32.MIN_VALUE; +i32.MAX_VALUE; +i64.MIN_VALUE; +i64.MAX_VALUE; +isize.MIN_VALUE; +isize.MAX_VALUE; +u8.MIN_VALUE; +u8.MAX_VALUE; +u16.MIN_VALUE; +u16.MAX_VALUE; +u32.MIN_VALUE; +u32.MAX_VALUE; +u64.MIN_VALUE; +u64.MAX_VALUE; +usize.MIN_VALUE; +usize.MAX_VALUE; +bool.MIN_VALUE; +bool.MAX_VALUE; +f32.MIN_SAFE_INTEGER; +f32.MAX_SAFE_INTEGER; +f64.MIN_SAFE_INTEGER; +f64.MAX_SAFE_INTEGER; diff --git a/tests/compiler/limits.wast b/tests/compiler/limits.wast new file mode 100644 index 00000000..3eda9ca7 --- /dev/null +++ b/tests/compiler/limits.wast @@ -0,0 +1,155 @@ +(module + (type $v (func)) + (global $i8.MIN_VALUE (mut i32) (i32.const -128)) + (global $i8.MAX_VALUE (mut i32) (i32.const 127)) + (global $i16.MIN_VALUE (mut i32) (i32.const -32768)) + (global $i16.MAX_VALUE (mut i32) (i32.const 32767)) + (global $i32.MIN_VALUE (mut i32) (i32.const -2147483648)) + (global $i32.MAX_VALUE (mut i32) (i32.const 2147483647)) + (global $i64.MIN_VALUE (mut i64) (i64.const -9223372036854775808)) + (global $i64.MAX_VALUE (mut i64) (i64.const 9223372036854775807)) + (global $u8.MIN_VALUE (mut i32) (i32.const 0)) + (global $u8.MAX_VALUE (mut i32) (i32.const 255)) + (global $u16.MIN_VALUE (mut i32) (i32.const 0)) + (global $u16.MAX_VALUE (mut i32) (i32.const 65535)) + (global $u32.MIN_VALUE (mut i32) (i32.const 0)) + (global $u32.MAX_VALUE (mut i32) (i32.const -1)) + (global $u64.MIN_VALUE (mut i64) (i64.const 0)) + (global $u64.MAX_VALUE (mut i64) (i64.const -1)) + (global $bool.MIN_VALUE (mut i32) (i32.const 0)) + (global $bool.MAX_VALUE (mut i32) (i32.const 1)) + (global $f32.MIN_SAFE_INTEGER (mut f32) (f32.const -16777215)) + (global $f32.MAX_SAFE_INTEGER (mut f32) (f32.const 16777215)) + (global $f64.MIN_SAFE_INTEGER (mut f64) (f64.const -9007199254740991)) + (global $f64.MAX_SAFE_INTEGER (mut f64) (f64.const 9007199254740991)) + (global $HEAP_START i32 (i32.const 4)) + (memory $0 1) + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (drop + (i32.const -128) + ) + (drop + (i32.const 127) + ) + (drop + (i32.const -32768) + ) + (drop + (i32.const 32767) + ) + (drop + (i32.const -2147483648) + ) + (drop + (i32.const 2147483647) + ) + (drop + (i64.const -9223372036854775808) + ) + (drop + (i64.const 9223372036854775807) + ) + (drop + (i32.const -2147483648) + ) + (drop + (i32.const 2147483647) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 255) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 65535) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const -1) + ) + (drop + (i64.const 0) + ) + (drop + (i64.const -1) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const -1) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 1) + ) + (drop + (f32.const -16777215) + ) + (drop + (f32.const 16777215) + ) + (drop + (f64.const -9007199254740991) + ) + (drop + (f64.const 9007199254740991) + ) + ) +) +(; +[program.elements] + clz + ctz + popcnt + rotl + rotr + abs + ceil + copysign + floor + max + min + nearest + sqrt + trunc + current_memory + grow_memory + unreachable + load + store + reinterpret + select + sizeof + changetype + isNaN + isFinite + assert + parseInt + parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize +[program.exports] + +;) diff --git a/tests/compiler/literals.wast b/tests/compiler/literals.wast index 65aef3c2..755e40c8 100644 --- a/tests/compiler/literals.wast +++ b/tests/compiler/literals.wast @@ -169,6 +169,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize [program.exports] ;) diff --git a/tests/compiler/logical.wast b/tests/compiler/logical.wast index 50de4022..d907b4bf 100644 --- a/tests/compiler/logical.wast +++ b/tests/compiler/logical.wast @@ -285,6 +285,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize logical/i logical/I logical/f diff --git a/tests/compiler/memcpy.wast b/tests/compiler/memcpy.wast index e34d9d70..d097fa93 100644 --- a/tests/compiler/memcpy.wast +++ b/tests/compiler/memcpy.wast @@ -2083,6 +2083,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize memcpy/memcpy memcpy/base memcpy/dest diff --git a/tests/compiler/namespace.wast b/tests/compiler/namespace.wast index e004dffe..5e17ba81 100644 --- a/tests/compiler/namespace.wast +++ b/tests/compiler/namespace.wast @@ -47,6 +47,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize namespace/Outer namespace/Outer.Inner namespace/Outer.Inner.aVar diff --git a/tests/compiler/reexport.wast b/tests/compiler/reexport.wast index efbdf5b6..d6945590 100644 --- a/tests/compiler/reexport.wast +++ b/tests/compiler/reexport.wast @@ -76,6 +76,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize export/add export/sub export/a diff --git a/tests/compiler/switch.wast b/tests/compiler/switch.wast index 955c09f7..f43f69ad 100644 --- a/tests/compiler/switch.wast +++ b/tests/compiler/switch.wast @@ -175,6 +175,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize switch/doSwitch switch/doSwitchDefaultFirst switch/doSwitchDefaultOmitted diff --git a/tests/compiler/ternary.wast b/tests/compiler/ternary.wast index 20243729..93339422 100644 --- a/tests/compiler/ternary.wast +++ b/tests/compiler/ternary.wast @@ -63,6 +63,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize ternary/a [program.exports] diff --git a/tests/compiler/tlsf.wast b/tests/compiler/tlsf.wast index 4b248c29..7cdd99cf 100644 --- a/tests/compiler/tlsf.wast +++ b/tests/compiler/tlsf.wast @@ -358,6 +358,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize tlsf/fls tlsf/ffs tlsf/ALIGN_SIZE_LOG2 diff --git a/tests/compiler/unary.wast b/tests/compiler/unary.wast index 11ffdc7b..d011f041 100644 --- a/tests/compiler/unary.wast +++ b/tests/compiler/unary.wast @@ -651,6 +651,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize unary/i unary/I unary/f diff --git a/tests/compiler/while.wast b/tests/compiler/while.wast index c9350a90..ca0af6ea 100644 --- a/tests/compiler/while.wast +++ b/tests/compiler/while.wast @@ -90,6 +90,19 @@ assert parseInt parseFloat + i8 + i16 + i32 + i64 + u8 + u16 + u32 + u64 + bool + f32 + f64 + isize + usize while/loopWhile while/loopWhileInWhile [program.exports]