From 2df318a7ec4725f46eb2fec0299163882a260521 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Fri, 12 Jan 2018 15:36:17 +0100 Subject: [PATCH] Implicitly alias stdlib exports as program globals, see #8 --- package-lock.json | 62 ++++++++++---- package.json | 4 +- src/ast.ts | 21 ++++- src/compiler.ts | 90 +++++++++++++------- src/module.ts | 2 +- src/parser.ts | 3 +- src/program.ts | 33 ++++---- src/types.ts | 4 +- std/assembly/array.ts | 2 - std/assembly/error.ts | 2 - std/assembly/heap.ts | 1 - std/assembly/map.ts | 1 - std/assembly/regexp.ts | 3 +- std/assembly/set.ts | 1 - std/assembly/string.ts | 3 - tests/compiler/fmod.wast | 20 +++-- tests/compiler/game-of-life.optimized.wast | 10 +-- tests/compiler/game-of-life.wast | 11 +-- tests/compiler/if.optimized.wast | 49 +++++++++++ tests/compiler/if.ts | 9 ++ tests/compiler/if.wast | 70 ++++++++++++++++ tests/compiler/logical.wast | 72 +++++++++------- tests/compiler/memcpy.wast | 5 +- tests/compiler/showcase.wast | 97 ++++++++++++---------- tests/compiler/std/array.wast | 3 + tests/compiler/std/heap.wast | 13 ++- tests/compiler/while.wast | 5 +- 27 files changed, 417 insertions(+), 179 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b6a6947..ff41be5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "requires": { "@types/events": "1.1.0", "@types/minimatch": "3.0.2", - "@types/node": "8.5.2" + "@types/node": "8.5.8" } }, "@types/long": { @@ -55,9 +55,9 @@ "dev": true }, "@types/node": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.2.tgz", - "integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.8.tgz", + "integrity": "sha512-8KmlRxwbKZfjUHFIt3q8TF5S2B+/E5BaAoo/3mgc5h6FJzqxXkCK/VMetO+IRDtwtU6HUvovHMBn+XRj7SV9Qg==", "dev": true }, "@types/strip-bom": { @@ -141,6 +141,15 @@ "normalize-path": "2.1.1" } }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -481,9 +490,9 @@ "dev": true }, "commander": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", - "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", "dev": true }, "concat-map": { @@ -771,6 +780,12 @@ "estraverse": "4.2.0" } }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, "esrecurse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", @@ -1204,6 +1219,16 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", @@ -2040,6 +2065,12 @@ "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", "dev": true }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "stream-browserify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -2202,28 +2233,29 @@ "dev": true }, "tslint": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", - "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", "dev": true, "requires": { "babel-code-frame": "6.26.0", "builtin-modules": "1.1.1", "chalk": "2.3.0", - "commander": "2.12.2", + "commander": "2.13.0", "diff": "3.4.0", "glob": "7.1.2", + "js-yaml": "3.10.0", "minimatch": "3.0.4", "resolve": "1.5.0", "semver": "5.4.1", "tslib": "1.8.1", - "tsutils": "2.14.0" + "tsutils": "2.16.0" } }, "tsutils": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.14.0.tgz", - "integrity": "sha512-f6axSMV0RoUufiKiRQgmRlN1c+Ag+mDaZjcd6bHdvplT/zyhuMCGqw3pJS8s3+0x4EVkdoQajs9PchdDZlguvw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.16.0.tgz", + "integrity": "sha512-9Ier/60O7OZRNPiw+or5QAtAY4kQA+WDiO/r6xOYATEyefH9bdfvTRLCxrYnFhQlZfET2vYXKfpr3Vw2BiArZw==", "dev": true, "requires": { "tslib": "1.8.1" diff --git a/package.json b/package.json index 0bf92f02..da6b76ad 100644 --- a/package.json +++ b/package.json @@ -21,14 +21,14 @@ "@types/glob": "^5.0.34", "@types/long": "^3.0.32", "@types/minimist": "^1.2.0", - "@types/node": "^8.5.2", + "@types/node": "^8.5.8", "chalk": "^2.3.0", "diff": "^3.4.0", "long": "^3.2.0", "source-map-support": "^0.5.0", "ts-loader": "^3.2.0", "ts-node": "^4.1.0", - "tslint": "^5.8.0", + "tslint": "^5.9.1", "typescript": "^2.6.2", "webpack": "^3.10.0" }, diff --git a/src/ast.ts b/src/ast.ts index a4e32897..d5abb7f7 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1176,12 +1176,20 @@ export enum ModifierKind { /** Base class of all statement nodes. */ export abstract class Statement extends Node { } +export enum SourceKind { + DEFAULT, + ENTRY, + STDLIB +} + /** A top-level source node. */ export class Source extends Node { kind = NodeKind.SOURCE; parent = null; + /** Source kind. */ + sourceKind: SourceKind; /** Path as provided to the parser. */ path: string; /** Normalized path. */ @@ -1194,21 +1202,24 @@ export class Source extends Node { text: string; /** Tokenizer reference. */ tokenizer: Tokenizer | null = null; - /** Whether an entry file or not. */ - isEntry: bool; /** Constructs a new source node. */ - constructor(path: string, text: string, isEntry: bool = false) { + constructor(path: string, text: string, kind: SourceKind = SourceKind.DEFAULT) { super(); + this.sourceKind = kind; this.path = path; this.normalizedPath = normalizePath(path, true); this.internalPath = mangleInternalPath(this.normalizedPath); this.statements = new Array(); this.range = new Range(this, 0, text.length); this.text = text; - this.isEntry = isEntry; } + /** Tests if this source is an entry file. */ + get isEntry(): bool { return this.sourceKind == SourceKind.ENTRY; } + /** Tests if this source is a stdlib file. */ + get isStdlib(): bool { return this.sourceKind == SourceKind.STDLIB; } + serialize(sb: string[]): void { for (var i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) { this.statements[i].serialize(sb); @@ -1236,6 +1247,8 @@ export abstract class DeclarationStatement extends Statement { /** Gets the mangled internal name of this declaration. */ get internalName(): string { return this._cachedInternalName === null ? this._cachedInternalName = mangleInternalName(this) : this._cachedInternalName; } + /** Tests if this is a top-level declaration. */ + get isTopLevel(): bool { return this.parent != null && this.parent.kind == NodeKind.SOURCE; } } /** Base class of all variable-like declaration statements with a type and initializer. */ diff --git a/src/compiler.ts b/src/compiler.ts index ce7f5aec..ff29563d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -54,6 +54,7 @@ import { NodeKind, TypeNode, Source, + SourceKind, Statement, BlockStatement, @@ -2113,26 +2114,24 @@ export class Compiler extends DiagnosticEmitter { left = this.module.createTeeLocal(tempLocal.index, left); } - // make a condition that checks !left in case an optimizer can take advantage of guaranteed 0 or 1 - // binaryen just switches the arms here, see: https://github.com/WebAssembly/binaryen/issues/1355 possiblyOverflows = this.currentType.is(TypeFlags.SMALL | TypeFlags.INTEGER); - condition = makeEqualsZero(left, this.currentType, this.module); + condition = makeIsTrueish(left, this.currentType, this.module); // simplify when cloning left without side effects was successful if (expr) expr = this.module.createIf( - condition, // if !left - expr, // then cloned left - right // else right + condition, // left + right, // ? right + expr // : cloned left ); // otherwise make use of the temp. local else { assert(tempLocal); expr = this.module.createIf( - condition, // if !left - this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()), - right + condition, + right, + this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()) ); } break; @@ -2150,26 +2149,24 @@ export class Compiler extends DiagnosticEmitter { left = this.module.createTeeLocal(tempLocal.index, left); } - // make a condition that checks !left in case an optimizer can take advantage of guaranteed 0 or 1 - // binaryen just switches the arms here, see: https://github.com/WebAssembly/binaryen/issues/1355 possiblyOverflows = this.currentType.is(TypeFlags.SMALL | TypeFlags.INTEGER); // if right already did - condition = makeEqualsZero(left, this.currentType, this.module); + condition = makeIsTrueish(left, this.currentType, this.module); // simplify when cloning left without side effects was successful if (expr) expr = this.module.createIf( - condition, // if !left - right, // then right - expr // else cloned left + condition, // left + expr, // ? cloned left + right // : right ); // otherwise make use of the temp. local else { assert(tempLocal); expr = this.module.createIf( - condition, // if !left - right, - this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()) + condition, + this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()), + right ); } break; @@ -2482,7 +2479,7 @@ export class Compiler extends DiagnosticEmitter { assert(contextualType.kind == TypeKind.USIZE); this.currentType = Type.usize64; } - return this.module.createI64(0, 0); + return this.module.createI64(0); } if (!contextualType.classType) { assert(contextualType.kind == TypeKind.USIZE); @@ -2706,7 +2703,7 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.U64: op = BinaryOp.AddI64; nativeType = NativeType.I64; - nativeOne = this.module.createI64(1, 0); + nativeOne = this.module.createI64(1); break; case TypeKind.F32: @@ -2754,7 +2751,7 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.U64: op = BinaryOp.SubI64; nativeType = NativeType.I64; - nativeOne = this.module.createI64(1, 0); + nativeOne = this.module.createI64(1); break; case TypeKind.F32: @@ -2851,7 +2848,7 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.I64: case TypeKind.U64: - expr = this.module.createBinary(BinaryOp.SubI64, this.module.createI64(0, 0), expr); + expr = this.module.createBinary(BinaryOp.SubI64, this.module.createI64(0), expr); break; case TypeKind.F32: @@ -2892,7 +2889,7 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.I64: case TypeKind.U64: - expr = this.module.createBinary(BinaryOp.AddI64, expr, this.module.createI64(1, 0)); + expr = this.module.createBinary(BinaryOp.AddI64, expr, this.module.createI64(1)); break; case TypeKind.F32: @@ -2934,7 +2931,7 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.I64: case TypeKind.U64: - expr = this.module.createBinary(BinaryOp.SubI64, expr, this.module.createI64(1, 0)); + expr = this.module.createBinary(BinaryOp.SubI64, expr, this.module.createI64(1)); break; case TypeKind.F32: @@ -2949,7 +2946,7 @@ export class Compiler extends DiagnosticEmitter { case Token.EXCLAMATION: // must wrap small integers expr = this.compileExpression(expression.operand, contextualType == Type.void ? Type.i32 : contextualType, ConversionKind.NONE); - expr = makeEqualsZero(expr, this.currentType, this.module); + expr = makeIsFalseish(expr, this.currentType, this.module); this.currentType = Type.bool; break; @@ -3052,7 +3049,7 @@ function makeInlineConstant(element: VariableLikeElement, module: Module): Expre case TypeKind.U64: return element.constantIntegerValue ? module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi) - : module.createI64(0, 0); + : module.createI64(0); case TypeKind.F32: return module.createF32((element).constantFloatValue); @@ -3114,7 +3111,8 @@ export function makeSmallIntegerWrap(expr: ExpressionRef, type: Type, module: Mo return expr; } -export function makeEqualsZero(expr: ExpressionRef, type: Type, module: Module): ExpressionRef { +/** Creates a comparison whether an expression is not 'true' in a broader sense. */ +export function makeIsFalseish(expr: ExpressionRef, type: Type, module: Module): ExpressionRef { switch (type.kind) { default: // any integer up to 32 bits @@ -3126,8 +3124,9 @@ export function makeEqualsZero(expr: ExpressionRef, type: Type, module: Module): expr = module.createUnary(UnaryOp.EqzI64, expr); break; - case TypeKind.ISIZE: case TypeKind.USIZE: + // TODO: strings + case TypeKind.ISIZE: expr = module.createUnary(type.size == 64 ? UnaryOp.EqzI64 : UnaryOp.EqzI32, expr); break; @@ -3144,3 +3143,38 @@ export function makeEqualsZero(expr: ExpressionRef, type: Type, module: Module): } return expr; } + +/** Creates a comparison whether an expression is 'true' in a broader sense. */ +export function makeIsTrueish(expr: ExpressionRef, type: Type, module: Module): ExpressionRef { + switch (type.kind) { + + default: // any integer up to 32 bits + expr = module.createBinary(BinaryOp.NeI32, expr, module.createI32(0)); + break; + + case TypeKind.I64: + case TypeKind.U64: + expr = module.createBinary(BinaryOp.NeI64, expr, module.createI64(0)); + break; + + case TypeKind.USIZE: + // TODO: strings + case TypeKind.ISIZE: + expr = type.size == 64 + ? module.createBinary(BinaryOp.NeI64, expr, module.createI64(0)) + : module.createBinary(BinaryOp.NeI32, expr, module.createI32(0)); + break; + + case TypeKind.F32: + expr = module.createBinary(BinaryOp.NeF32, expr, module.createF32(0)); + break; + + case TypeKind.F64: + expr = module.createBinary(BinaryOp.NeF64, expr, module.createF64(0)); + break; + + case TypeKind.VOID: + throw new Error("concrete type expected"); + } + return expr; +} diff --git a/src/module.ts b/src/module.ts index fc08d820..df6816a7 100644 --- a/src/module.ts +++ b/src/module.ts @@ -306,7 +306,7 @@ export class Module { return _BinaryenConst(this.ref, this.lit); } - createI64(lo: i32, hi: i32): ExpressionRef { + createI64(lo: i32, hi: i32 = 0): ExpressionRef { if (this.noEmit) return 0; _BinaryenLiteralInt64(this.lit, lo, hi); return _BinaryenConst(this.ref, this.lit); diff --git a/src/parser.ts b/src/parser.ts index e6168143..80acd2e7 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -30,6 +30,7 @@ import { Node, NodeKind, Source, + SourceKind, TypeNode, Expression, @@ -104,7 +105,7 @@ export class Parser extends DiagnosticEmitter { return; // already parsed this.seenlog.add(normalizedPath); - var source = new Source(path, text, isEntry); + var source = new Source(path, text, isEntry ? SourceKind.ENTRY : path.startsWith("std:") ? SourceKind.STDLIB : SourceKind.DEFAULT); this.program.sources.push(source); var tn = new Tokenizer(source, this.program.diagnostics); diff --git a/src/program.ts b/src/program.ts index d71761fb..6570186a 100644 --- a/src/program.ts +++ b/src/program.ts @@ -269,6 +269,15 @@ export class Program extends DiagnosticEmitter { } while (true); } + private checkGlobalAlias(element: Element, declaration: DeclarationStatement) { + if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(declaration.parent).kind == NodeKind.SOURCE && element.isExported)) { + if (this.elements.has(declaration.name.name)) + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, element.internalName); + else + this.elements.set(declaration.name.name, element); + } + } + private initializeClass(declaration: ClassDeclaration, queuedDerivedClasses: ClassPrototype[], namespace: Element | null = null): void { var internalName = declaration.internalName; if (this.elements.has(internalName)) { @@ -279,13 +288,8 @@ export class Program extends DiagnosticEmitter { prototype.namespace = namespace; this.elements.set(internalName, prototype); - // add program-level alias if annotated as @global - if (hasDecorator("global", declaration.decorators)) { - if (this.elements.has(declaration.name.name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); - else - this.elements.set(declaration.name.name, prototype); - } + this.checkGlobalAlias(prototype, declaration); + if (hasDecorator("struct", declaration.decorators)) { prototype.isStruct = true; if (declaration.implementsTypes && declaration.implementsTypes.length) @@ -522,6 +526,8 @@ export class Program extends DiagnosticEmitter { enm.namespace = namespace; this.elements.set(internalName, enm); + this.checkGlobalAlias(enm, declaration); + if (namespace) { if (namespace.members) { if (namespace.members.has(declaration.name.name)) { @@ -648,12 +654,7 @@ export class Program extends DiagnosticEmitter { prototype.namespace = namespace; this.elements.set(internalName, prototype); - if (hasDecorator("global", declaration.decorators)) { - if (this.elements.has(declaration.name.name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); - else - this.elements.set(declaration.name.name, prototype); - } + this.checkGlobalAlias(prototype, declaration); if (namespace) { if (namespace.members) { @@ -743,6 +744,8 @@ export class Program extends DiagnosticEmitter { prototype.namespace = namespace; this.elements.set(internalName, prototype); + this.checkGlobalAlias(prototype, declaration); + if (namespace) { if (namespace.members) { if (namespace.members.has(prototype.internalName)) { @@ -791,6 +794,7 @@ export class Program extends DiagnosticEmitter { namespace = new Namespace(this, declaration.name.name, internalName, declaration); namespace.namespace = parentNamespace; this.elements.set(internalName, namespace); + this.checkGlobalAlias(namespace, declaration); } if (parentNamespace) { @@ -875,7 +879,8 @@ export class Program extends DiagnosticEmitter { global.namespace = namespace; this.elements.set(internalName, global); - if (hasDecorator("global", declaration.decorators)) { + // differs a bit from this.checkGlobalAlias in that it checks the statement's parent + if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(statement.parent).kind == NodeKind.SOURCE && global.isExported)) { if (this.elements.has(declaration.name.name)) this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); else diff --git a/src/types.ts b/src/types.ts index a83be9e7..58b30d2b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -219,7 +219,7 @@ export class Type { case TypeKind.I64: case TypeKind.U64: - return module.createI64(0, 0); + return module.createI64(0); case TypeKind.F32: return module.createF32(0); @@ -247,7 +247,7 @@ export class Type { case TypeKind.I64: case TypeKind.U64: - return module.createI64(1, 0); + return module.createI64(1); case TypeKind.F32: return module.createF32(1); diff --git a/std/assembly/array.ts b/std/assembly/array.ts index 67c90aa4..42d35eb8 100644 --- a/std/assembly/array.ts +++ b/std/assembly/array.ts @@ -1,4 +1,3 @@ -@global export class Array { private ptr: usize; @@ -39,7 +38,6 @@ export class Array { // TODO } -@global @struct export class CArray { diff --git a/std/assembly/error.ts b/std/assembly/error.ts index 05e99b6d..004bdfbe 100644 --- a/std/assembly/error.ts +++ b/std/assembly/error.ts @@ -1,4 +1,3 @@ -@global export class Error { name: string = "Error"; @@ -10,7 +9,6 @@ export class Error { } } -@global export class RangeError extends Error { name: string = "RangeError"; } diff --git a/std/assembly/heap.ts b/std/assembly/heap.ts index deffef55..9c5bab91 100644 --- a/std/assembly/heap.ts +++ b/std/assembly/heap.ts @@ -6,7 +6,6 @@ var HEAP_OFFSET: usize = HEAP_BASE; // HEAP_BASE is a constant generated by the // TODO: maybe tlsf -@global export class Heap { static get used(): usize { return HEAP_OFFSET - HEAP_BASE; } diff --git a/std/assembly/map.ts b/std/assembly/map.ts index 3281d192..06983725 100644 --- a/std/assembly/map.ts +++ b/std/assembly/map.ts @@ -1,4 +1,3 @@ -@global export class Map { // TODO } diff --git a/std/assembly/regexp.ts b/std/assembly/regexp.ts index daf44cf5..8ed6063e 100644 --- a/std/assembly/regexp.ts +++ b/std/assembly/regexp.ts @@ -1,5 +1,4 @@ -@global -class RegExp { +export class RegExp { // @binding(CALL_NEW, [ STRING, STRING], OBJECT_HANDLE) constructor(pattern: string, flags: string = "") { throw new Error("unreachable"); } diff --git a/std/assembly/set.ts b/std/assembly/set.ts index 22c0a47b..14792627 100644 --- a/std/assembly/set.ts +++ b/std/assembly/set.ts @@ -1,4 +1,3 @@ -@global export class Set { // TODO } diff --git a/std/assembly/string.ts b/std/assembly/string.ts index 2ed5cac2..1c32f127 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -1,6 +1,5 @@ const EMPTY: String = changetype(""); -@global export class String { // [key: number]: string; @@ -197,13 +196,11 @@ function isWhiteSpaceOrLineTerminator(c: u16): bool { } } -// @global // @binding(CALL, [ STRING, PASS_THRU ], PASS_THRU) export function parseInt(str: string, radix: i32 = 10): f64 { throw new Error("not implemented"); } -// @global // @binding(CALL, [ STRING ], PASS_THRU) export function parseFloat(str: string): f64 { throw new Error("not implemented"); diff --git a/tests/compiler/fmod.wast b/tests/compiler/fmod.wast index 9fb8771c..7389851e 100644 --- a/tests/compiler/fmod.wast +++ b/tests/compiler/fmod.wast @@ -72,11 +72,11 @@ (if (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i64.eq (i64.shl @@ -86,24 +86,26 @@ (i64.const 0) ) ) + (i32.const 0) ) + (get_local $8) (f64.ne (tee_local $7 (get_local $1) ) (get_local $7) ) - (get_local $8) ) (i32.const 1) ) ) + (i32.const 0) ) + (get_local $8) (i32.eq (get_local $4) (i32.const 2047) ) - (get_local $8) ) (i32.const 1) ) @@ -542,11 +544,11 @@ (if (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.eq (i32.shl @@ -556,24 +558,26 @@ (i32.const 0) ) ) + (i32.const 0) ) + (get_local $8) (f32.ne (tee_local $7 (get_local $1) ) (get_local $7) ) - (get_local $8) ) (i32.const 1) ) ) + (i32.const 0) ) + (get_local $8) (i32.eq (get_local $4) (i32.const 255) ) - (get_local $8) ) (i32.const 1) ) diff --git a/tests/compiler/game-of-life.optimized.wast b/tests/compiler/game-of-life.optimized.wast index 459b18bc..656cfef5 100644 --- a/tests/compiler/game-of-life.optimized.wast +++ b/tests/compiler/game-of-life.optimized.wast @@ -211,7 +211,11 @@ (if (i32.and (if (result i32) - (i32.ge_u + (i32.lt_u + (get_local $2) + (i32.const 2) + ) + (i32.lt_u (get_local $2) (i32.const 2) ) @@ -219,10 +223,6 @@ (get_local $2) (i32.const 3) ) - (i32.lt_u - (get_local $2) - (i32.const 2) - ) ) (i32.const 1) ) diff --git a/tests/compiler/game-of-life.wast b/tests/compiler/game-of-life.wast index 7c0b0adf..ed9ea503 100644 --- a/tests/compiler/game-of-life.wast +++ b/tests/compiler/game-of-life.wast @@ -237,20 +237,21 @@ (if (i32.and (if (result i32) - (i32.eqz + (i32.ne (i32.lt_u (get_local $8) (i32.const 2) ) - ) - (i32.gt_u - (get_local $8) - (i32.const 3) + (i32.const 0) ) (i32.lt_u (get_local $8) (i32.const 2) ) + (i32.gt_u + (get_local $8) + (i32.const 3) + ) ) (i32.const 1) ) diff --git a/tests/compiler/if.optimized.wast b/tests/compiler/if.optimized.wast index 6f5d3b2f..ee4e5d5d 100644 --- a/tests/compiler/if.optimized.wast +++ b/tests/compiler/if.optimized.wast @@ -1,10 +1,12 @@ (module (type $ii (func (param i32) (result i32))) + (type $v (func)) (memory $0 1) (export "ifThenElse" (func $if/ifThenElse)) (export "ifThen" (func $if/ifThen)) (export "ifThenElseBlock" (func $if/ifThenElse)) (export "memory" (memory $0)) + (start $start) (func $if/ifThenElse (; 0 ;) (type $ii) (param $0 i32) (result i32) (if (result i32) (get_local $0) @@ -21,4 +23,51 @@ ) (i32.const 0) ) + (func $start (; 2 ;) (type $v) + (if + (call $if/ifThenElse + (i32.const 0) + ) + (unreachable) + ) + (if + (i32.ne + (call $if/ifThenElse + (i32.const 1) + ) + (i32.const 1) + ) + (unreachable) + ) + (if + (call $if/ifThen + (i32.const 0) + ) + (unreachable) + ) + (if + (i32.ne + (call $if/ifThen + (i32.const 1) + ) + (i32.const 1) + ) + (unreachable) + ) + (if + (call $if/ifThenElse + (i32.const 0) + ) + (unreachable) + ) + (if + (i32.ne + (call $if/ifThenElse + (i32.const 1) + ) + (i32.const 1) + ) + (unreachable) + ) + ) ) diff --git a/tests/compiler/if.ts b/tests/compiler/if.ts index 6606acb1..c41eb7a7 100644 --- a/tests/compiler/if.ts +++ b/tests/compiler/if.ts @@ -5,12 +5,18 @@ export function ifThenElse(n: i32): bool { return false; } +assert(ifThenElse(0) == false); +assert(ifThenElse(1) == true); + export function ifThen(n: i32): bool { if (n) return true; return false; } +assert(ifThen(0) == false); +assert(ifThen(1) == true); + export function ifThenElseBlock(n: i32): bool { if (n) { ; // nop @@ -20,3 +26,6 @@ export function ifThenElseBlock(n: i32): bool { return false; } } + +assert(ifThenElseBlock(0) == false); +assert(ifThenElseBlock(1) == true); diff --git a/tests/compiler/if.wast b/tests/compiler/if.wast index f74f60f4..fa697e5e 100644 --- a/tests/compiler/if.wast +++ b/tests/compiler/if.wast @@ -1,11 +1,13 @@ (module (type $ii (func (param i32) (result i32))) + (type $v (func)) (global $HEAP_BASE i32 (i32.const 4)) (memory $0 1) (export "ifThenElse" (func $if/ifThenElse)) (export "ifThen" (func $if/ifThen)) (export "ifThenElseBlock" (func $if/ifThenElseBlock)) (export "memory" (memory $0)) + (start $start) (func $if/ifThenElse (; 0 ;) (type $ii) (param $0 i32) (result i32) (if (get_local $0) @@ -45,6 +47,74 @@ ) ) ) + (func $start (; 3 ;) (type $v) + (if + (i32.eqz + (i32.eq + (call $if/ifThenElse + (i32.const 0) + ) + (i32.const 0) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (call $if/ifThenElse + (i32.const 1) + ) + (i32.const 1) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (call $if/ifThen + (i32.const 0) + ) + (i32.const 0) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (call $if/ifThen + (i32.const 1) + ) + (i32.const 1) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (call $if/ifThenElseBlock + (i32.const 0) + ) + (i32.const 0) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (call $if/ifThenElseBlock + (i32.const 1) + ) + (i32.const 1) + ) + ) + (unreachable) + ) + ) ) (; [program.elements] diff --git a/tests/compiler/logical.wast b/tests/compiler/logical.wast index 2fcf969b..6f6b985e 100644 --- a/tests/compiler/logical.wast +++ b/tests/compiler/logical.wast @@ -13,85 +13,90 @@ (local $1 f64) (drop (if (result i32) - (i32.eqz + (i32.ne + (i32.const 0) (i32.const 0) ) - (i32.const 0) (unreachable) + (i32.const 0) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (f64.const 0) (f64.const 0) ) - (f64.const 0) (unreachable) + (f64.const 0) ) ) (drop (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (unreachable) (i32.const 1) + (unreachable) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (unreachable) (f64.const 1) + (unreachable) ) ) (drop (if (result i32) - (i32.eqz + (i32.ne (tee_local $0 (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (i32.const 1) (i32.const 2) + (i32.const 1) ) ) + (i32.const 0) ) - (unreachable) (get_local $0) + (unreachable) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (tee_local $1 (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (f64.const 1) (f64.const 2) + (f64.const 1) ) ) (f64.const 0) ) - (unreachable) (get_local $1) + (unreachable) ) ) (set_global $logical/i (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (i32.const 1) (i32.const 2) + (i32.const 1) ) ) (if @@ -105,11 +110,12 @@ ) (set_global $logical/i (if (result i32) - (i32.eqz + (i32.ne + (i32.const 0) (i32.const 0) ) - (i32.const 1) (i32.const 0) + (i32.const 1) ) ) (if @@ -123,11 +129,12 @@ ) (set_global $logical/I (if (result i64) - (i64.eqz + (i64.ne (i64.const 1) + (i64.const 0) ) - (i64.const 1) (i64.const 2) + (i64.const 1) ) ) (if @@ -141,11 +148,12 @@ ) (set_global $logical/I (if (result i64) - (i64.eqz + (i64.ne + (i64.const 0) (i64.const 0) ) - (i64.const 1) (i64.const 0) + (i64.const 1) ) ) (if @@ -159,12 +167,12 @@ ) (set_global $logical/f (if (result f32) - (f32.eq + (f32.ne (f32.const 1) (f32.const 0) ) - (f32.const 1) (f32.const 2) + (f32.const 1) ) ) (if @@ -178,12 +186,12 @@ ) (set_global $logical/f (if (result f32) - (f32.eq + (f32.ne (f32.const 0) (f32.const 0) ) - (f32.const 1) (f32.const 0) + (f32.const 1) ) ) (if @@ -197,12 +205,12 @@ ) (set_global $logical/F (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (f64.const 1) (f64.const 2) + (f64.const 1) ) ) (if @@ -216,12 +224,12 @@ ) (set_global $logical/F (if (result f64) - (f64.eq + (f64.ne (f64.const 0) (f64.const 0) ) - (f64.const 1) (f64.const 0) + (f64.const 1) ) ) (if diff --git a/tests/compiler/memcpy.wast b/tests/compiler/memcpy.wast index 5301ef07..b9b3b85a 100644 --- a/tests/compiler/memcpy.wast +++ b/tests/compiler/memcpy.wast @@ -27,14 +27,15 @@ (loop $continue|0 (if (if (result i32) - (i32.eqz + (i32.ne (get_local $2) + (i32.const 0) ) - (get_local $2) (i32.rem_u (get_local $4) (i32.const 4) ) + (get_local $2) ) (block (block diff --git a/tests/compiler/showcase.wast b/tests/compiler/showcase.wast index 056b4f78..4885d267 100644 --- a/tests/compiler/showcase.wast +++ b/tests/compiler/showcase.wast @@ -135,14 +135,15 @@ (loop $continue|0 (if (if (result i32) - (i32.eqz + (i32.ne (get_local $2) + (i32.const 0) ) - (get_local $2) (i32.rem_u (get_local $4) (i32.const 4) ) + (get_local $2) ) (block (block @@ -1992,11 +1993,11 @@ (if (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i64.eq (i64.shl @@ -2006,24 +2007,26 @@ (i64.const 0) ) ) + (i32.const 0) ) + (get_local $8) (f64.ne (tee_local $7 (get_local $1) ) (get_local $7) ) - (get_local $8) ) (i32.const 1) ) ) + (i32.const 0) ) + (get_local $8) (i32.eq (get_local $4) (i32.const 2047) ) - (get_local $8) ) (i32.const 1) ) @@ -2462,11 +2465,11 @@ (if (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.and (if (result i32) - (i32.eqz + (i32.ne (tee_local $8 (i32.eq (i32.shl @@ -2476,24 +2479,26 @@ (i32.const 0) ) ) + (i32.const 0) ) + (get_local $8) (f32.ne (tee_local $7 (get_local $1) ) (get_local $7) ) - (get_local $8) ) (i32.const 1) ) ) + (i32.const 0) ) + (get_local $8) (i32.eq (get_local $4) (i32.const 255) ) - (get_local $8) ) (i32.const 1) ) @@ -4231,85 +4236,90 @@ ) (drop (if (result i32) - (i32.eqz + (i32.ne + (i32.const 0) (i32.const 0) ) - (i32.const 0) (unreachable) + (i32.const 0) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (f64.const 0) (f64.const 0) ) - (f64.const 0) (unreachable) + (f64.const 0) ) ) (drop (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (unreachable) (i32.const 1) + (unreachable) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (unreachable) (f64.const 1) + (unreachable) ) ) (drop (if (result i32) - (i32.eqz + (i32.ne (tee_local $0 (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (i32.const 1) (i32.const 2) + (i32.const 1) ) ) + (i32.const 0) ) - (unreachable) (get_local $0) + (unreachable) ) ) (drop (if (result f64) - (f64.eq + (f64.ne (tee_local $3 (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (f64.const 1) (f64.const 2) + (f64.const 1) ) ) (f64.const 0) ) - (unreachable) (get_local $3) + (unreachable) ) ) (set_global $logical/i (if (result i32) - (i32.eqz + (i32.ne (i32.const 1) + (i32.const 0) ) - (i32.const 1) (i32.const 2) + (i32.const 1) ) ) (if @@ -4323,11 +4333,12 @@ ) (set_global $logical/i (if (result i32) - (i32.eqz + (i32.ne + (i32.const 0) (i32.const 0) ) - (i32.const 1) (i32.const 0) + (i32.const 1) ) ) (if @@ -4341,11 +4352,12 @@ ) (set_global $logical/I (if (result i64) - (i64.eqz + (i64.ne (i64.const 1) + (i64.const 0) ) - (i64.const 1) (i64.const 2) + (i64.const 1) ) ) (if @@ -4359,11 +4371,12 @@ ) (set_global $logical/I (if (result i64) - (i64.eqz + (i64.ne + (i64.const 0) (i64.const 0) ) - (i64.const 1) (i64.const 0) + (i64.const 1) ) ) (if @@ -4377,12 +4390,12 @@ ) (set_global $logical/f (if (result f32) - (f32.eq + (f32.ne (f32.const 1) (f32.const 0) ) - (f32.const 1) (f32.const 2) + (f32.const 1) ) ) (if @@ -4396,12 +4409,12 @@ ) (set_global $logical/f (if (result f32) - (f32.eq + (f32.ne (f32.const 0) (f32.const 0) ) - (f32.const 1) (f32.const 0) + (f32.const 1) ) ) (if @@ -4415,12 +4428,12 @@ ) (set_global $logical/F (if (result f64) - (f64.eq + (f64.ne (f64.const 1) (f64.const 0) ) - (f64.const 1) (f64.const 2) + (f64.const 1) ) ) (if @@ -4434,12 +4447,12 @@ ) (set_global $logical/F (if (result f64) - (f64.eq + (f64.ne (f64.const 0) (f64.const 0) ) - (f64.const 1) (f64.const 0) + (f64.const 1) ) ) (if diff --git a/tests/compiler/std/array.wast b/tests/compiler/std/array.wast index 9936be1d..03f8e437 100644 --- a/tests/compiler/std/array.wast +++ b/tests/compiler/std/array.wast @@ -80,7 +80,9 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseFloat + FUNCTION_PROTOTYPE: parseFloat [program.exports] CLASS_PROTOTYPE: std:array/Array CLASS_PROTOTYPE: std:array/CArray @@ -88,6 +90,7 @@ CLASS_PROTOTYPE: std:error/RangeError CLASS_PROTOTYPE: std:heap/Heap CLASS_PROTOTYPE: std:map/Map + CLASS_PROTOTYPE: std:regexp/RegExp CLASS_PROTOTYPE: std:set/Set CLASS_PROTOTYPE: std:string/String FUNCTION_PROTOTYPE: std:string/parseInt diff --git a/tests/compiler/std/heap.wast b/tests/compiler/std/heap.wast index adeeee37..e12a33ea 100644 --- a/tests/compiler/std/heap.wast +++ b/tests/compiler/std/heap.wast @@ -528,14 +528,15 @@ (loop $continue|0 (if (if (result i32) - (i32.eqz + (i32.ne (get_local $2) + (i32.const 0) ) - (get_local $2) (i32.rem_u (get_local $1) (i32.const 4) ) + (get_local $2) ) (block (block @@ -2337,10 +2338,10 @@ (loop $continue|0 (if (if (result i32) - (i32.eqz + (i32.ne (get_local $2) + (i32.const 0) ) - (get_local $2) (i32.eq (i32.load8_u (get_local $0) @@ -2349,6 +2350,7 @@ (get_local $1) ) ) + (get_local $2) ) (block (block @@ -2600,7 +2602,9 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseFloat + FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/heap/size GLOBAL: std/heap/ptr1 GLOBAL: std/heap/ptr2 @@ -2612,6 +2616,7 @@ CLASS_PROTOTYPE: std:error/RangeError CLASS_PROTOTYPE: std:heap/Heap CLASS_PROTOTYPE: std:map/Map + CLASS_PROTOTYPE: std:regexp/RegExp CLASS_PROTOTYPE: std:set/Set CLASS_PROTOTYPE: std:string/String FUNCTION_PROTOTYPE: std:string/parseInt diff --git a/tests/compiler/while.wast b/tests/compiler/while.wast index be1c8824..9c6c30b1 100644 --- a/tests/compiler/while.wast +++ b/tests/compiler/while.wast @@ -160,7 +160,7 @@ (loop $continue|3 (if (if (result i32) - (i32.eqz + (i32.ne (tee_local $0 (block (result i32) (set_local $0 @@ -175,8 +175,8 @@ (get_local $0) ) ) + (i32.const 0) ) - (get_local $0) (block (result i32) (set_global $while/m (i32.add @@ -186,6 +186,7 @@ ) (get_global $while/m) ) + (get_local $0) ) (block (nop)