Implicitly alias stdlib exports as program globals, see #8

This commit is contained in:
dcodeIO 2018-01-12 15:36:17 +01:00
parent 3980e53bb7
commit 2df318a7ec
27 changed files with 417 additions and 179 deletions

62
package-lock.json generated
View File

@ -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"

View File

@ -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"
},

View File

@ -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. */

View File

@ -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((<Local>tempLocal).index, this.currentType.toNativeType()),
right
condition,
right,
this.module.createGetLocal((<Local>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((<Local>tempLocal).index, this.currentType.toNativeType())
condition,
this.module.createGetLocal((<Local>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((<VariableLikeElement>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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -1,4 +1,3 @@
@global
export class Array<T> {
private ptr: usize;
@ -39,7 +38,6 @@ export class Array<T> {
// TODO
}
@global
@struct
export class CArray<T> {

View File

@ -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";
}

View File

@ -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; }

View File

@ -1,4 +1,3 @@
@global
export class Map<K,V> {
// TODO
}

View File

@ -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"); }

View File

@ -1,4 +1,3 @@
@global
export class Set<T> {
// TODO
}

View File

@ -1,6 +1,5 @@
const EMPTY: String = changetype<String>("");
@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");

View File

@ -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)
)

View File

@ -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)
)

View File

@ -237,20 +237,21 @@
(if
(i32.and
(if (result i32)
(i32.eqz
(i32.ne
(i32.lt_u
(get_local $8)
(i32.const 2)
)
(i32.const 0)
)
(i32.lt_u
(get_local $8)
(i32.const 2)
)
(i32.gt_u
(get_local $8)
(i32.const 3)
)
(i32.lt_u
(get_local $8)
(i32.const 2)
)
)
(i32.const 1)
)

View File

@ -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)
)
)
)

View File

@ -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);

View File

@ -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]

View File

@ -13,85 +13,90 @@
(local $1 f64)
(drop
(if (result i32)
(i32.eqz
(i32.ne
(i32.const 0)
(i32.const 0)
)
(unreachable)
(i32.const 0)
)
)
(drop
(if (result f64)
(f64.ne
(f64.const 0)
(f64.const 0)
)
(unreachable)
(f64.const 0)
)
)
(drop
(if (result i32)
(i32.ne
(i32.const 1)
(i32.const 0)
)
(i32.const 1)
(unreachable)
)
)
(drop
(if (result f64)
(f64.eq
(f64.const 0)
(f64.ne
(f64.const 1)
(f64.const 0)
)
(f64.const 0)
(f64.const 1)
(unreachable)
)
)
(drop
(if (result i32)
(i32.eqz
(i32.const 1)
)
(unreachable)
(i32.const 1)
)
)
(drop
(if (result f64)
(f64.eq
(f64.const 1)
(f64.const 0)
)
(unreachable)
(f64.const 1)
)
)
(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

View File

@ -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

View File

@ -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)
)
(unreachable)
(i32.const 0)
)
)
(drop
(if (result f64)
(f64.ne
(f64.const 0)
(f64.const 0)
)
(unreachable)
(f64.const 0)
)
)
(drop
(if (result i32)
(i32.ne
(i32.const 1)
(i32.const 0)
)
(i32.const 1)
(unreachable)
)
)
(drop
(if (result f64)
(f64.eq
(f64.const 0)
(f64.ne
(f64.const 1)
(f64.const 0)
)
(f64.const 0)
(f64.const 1)
(unreachable)
)
)
(drop
(if (result i32)
(i32.eqz
(i32.const 1)
)
(unreachable)
(i32.const 1)
)
)
(drop
(if (result f64)
(f64.eq
(f64.const 1)
(f64.const 0)
)
(unreachable)
(f64.const 1)
)
)
(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

View File

@ -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

View File

@ -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

View File

@ -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)