PSON decoder example using namespaced imports

This commit is contained in:
dcodeIO 2017-12-30 05:11:58 +01:00
parent c67f87a988
commit 2888ba14ad
41 changed files with 1283 additions and 336 deletions

View File

@ -3,7 +3,7 @@
[![Build Status](https://travis-ci.org/AssemblyScript/assemblyscript.svg?branch=master)](https://travis-ci.org/AssemblyScript/assemblyscript)
**AssemblyScript** compiles strictly typed [TypeScript](http://www.typescriptlang.org) to [WebAssembly](http://webassembly.org) using [Binaryen](https://github.com/WebAssembly/binaryen). Unlike more complex toolchains, `asc` generates minimal WebAssembly modules while being just an `npm install` away.
**AssemblyScript** compiles strictly typed [TypeScript](http://www.typescriptlang.org) to [WebAssembly](http://webassembly.org) using [Binaryen](https://github.com/WebAssembly/binaryen). Unlike other toolchains, `asc` generates minimal WebAssembly modules while being just an `npm install` away.
Examples
--------
@ -16,6 +16,9 @@ A few early examples to get an idea:
* **[i64 polyfill](./examples/i64-polyfill)**<br />
Exposes WebAssembly's i64 operations to JavaScript using 32-bit integers (low and high bits).
* **[PSON decoder](./examples/pson)**<br />
A PSON decoder implemented in AssemblyScript.
Or browse the [compiler tests](./tests/compiler) for a more in-depth overview of what's supported already.
Getting started

2
examples/.gitignore vendored
View File

@ -1,3 +1,5 @@
*.wast
*.wasm
node_modules/
npm-debug.log
package-lock.json

View File

@ -1,8 +1,8 @@
// A simplified version of the game of life as seen on http://dcode.io
var w: u32; // width
var h: u32; // height
var s: u32; // total size
var w: u32, // width
h: u32, // height
s: u32; // total size
/** Initializes width and height. */
export function init(w_: u32, h_: u32): void {
@ -13,21 +13,18 @@ export function init(w_: u32, h_: u32): void {
/** Performs one step. */
export function step(): void {
var y: u32, ym1: u32, yp1: u32; // y, y-1 and y+1
var x: u32, xm1: u32, xp1: u32; // x, x-1 and x+1
var hm1: u32 = h - 1, wm1: u32 = w - 1;
var n: u32, v: u8, c: u32 = 0;
for (y = 0; y < h; ++y) {
ym1 = select<u32>(hm1, y - 1, y == 0);
var hm1 = h - 1,
wm1 = w - 1;
for (var y: u32 = 0; y < h; ++y) {
var ym1 = select<u32>(hm1, y - 1, y == 0),
yp1 = select<u32>(0, y + 1, y == hm1);
for (x = 0; x < w; ++x) {
xm1 = select<u32>(wm1, x - 1, x == 0);
for (var x: u32 = 0; x < w; ++x) {
var xm1 = select<u32>(wm1, x - 1, x == 0),
xp1 = select<u32>(0, x + 1, x == wm1);
n = load<u8>(ym1 * w + xm1) + load<u8>(ym1 * w + x) + load<u8>(ym1 * w + xp1)
var n = load<u8>(ym1 * w + xm1) + load<u8>(ym1 * w + x) + load<u8>(ym1 * w + xp1)
+ load<u8>(y * w + xm1) + load<u8>(y * w + xp1)
+ load<u8>(yp1 * w + xm1) + load<u8>(yp1 * w + x) + load<u8>(yp1 * w + xp1);
v = load<u8>(y * w + x);
if (v) {
if (load<u8>(y * w + x)) {
if (n < 2 || n > 3)
store<u8>(s + y * w + x, 0);
} else if (n == 3)

View File

@ -1,5 +1,5 @@
let lo: u32;
let hi: u32;
var lo: u32,
hi: u32;
export function getLo(): u32 {
return lo;

19
examples/pson/README.md Normal file
View File

@ -0,0 +1,19 @@
PSON decoder in WebAssembly
===========================
An [AssemblyScript](http://assemblyscript.org) example. Decodes a [PSON](https://github.com/dcodeIO/PSON) encoded buffer.
Instructions
------------
To build [assembly/pson.ts](./assembly/pson.ts) to an untouched and an optimized `.wasm` including their respective `.wast` representations, run:
```
$> npm run build
```
Afterwards, to run the included test, do:
```
$> npm test
```

View File

@ -0,0 +1,156 @@
const enum Token {
ZERO = 0x00,
MAX = 0xEF,
NULL = 0xf0,
TRUE = 0xf1,
FALSE = 0xf2,
EOBJECT = 0xf3,
EARRAY = 0xf4,
ESTRING = 0xf5,
OBJECT = 0xf6,
ARRAY = 0xf7,
INTEGER = 0xf8,
LONG = 0xf9,
FLOAT = 0xfa,
DOUBLE = 0xfb,
STRING = 0xfc,
STRING_ADD = 0xfd,
STRING_GET = 0xfe,
BINARY = 0xff
}
namespace pson {
export declare function onNull(): void;
export declare function onTrue(): void;
export declare function onFalse(): void;
export declare function onEObject(): void;
export declare function onEArray(): void;
export declare function onEString(): void;
export declare function onObject(size: u32): void;
export declare function onArray(size: u32): void;
export declare function onInteger(value: i32): void;
export declare function onLong(valueLow: i32, valueHigh: i32): void;
export declare function onFloat(value: f32): void;
export declare function onDouble(value: f64): void;
export declare function onString(offset: usize, length: u32): void;
export declare function onBinary(offset: usize, length: u32): void;
export declare function onTruncated(): void;
}
var offset: usize = 0;
export function decode(length: usize): void {
offset = 0;
while (offset < length)
decodeValue();
if (offset != length)
pson.onTruncated();
}
function decodeValue(): void {
var token: u32 = load<u8>(offset++);
var size: u32;
var long: u64;
switch (token) {
case Token.NULL:
pson.onNull();
break;
case Token.TRUE:
pson.onTrue();
break;
case Token.FALSE:
pson.onFalse();
break;
case Token.EOBJECT:
pson.onEObject();
break;
case Token.EARRAY:
pson.onEArray();
break;
case Token.ESTRING:
pson.onEString();
break;
case Token.OBJECT:
pson.onObject(size = readVarint32());
while (size--) {
decodeValue();
decodeValue();
}
break;
case Token.ARRAY:
pson.onArray(size = readVarint32());
while (size--)
decodeValue();
break;
case Token.INTEGER:
pson.onInteger(((size = readVarint32()) >> 1) ^ -(size & 1));
break;
case Token.LONG:
long = ((long = readVarint64()) >> 1) ^ -(long & 1);
pson.onLong(<i32>long, <i32>(long >>> 32));
break;
case Token.FLOAT:
pson.onFloat(load<f32>(offset));
offset += 4;
break;
case Token.DOUBLE:
pson.onDouble(load<f64>(offset));
offset += 8;
break;
case Token.STRING:
size = readVarint32();
pson.onString(offset, size);
offset += size;
break;
case Token.STRING_ADD:
case Token.STRING_GET:
// could be implemented via imports as well, but isn't necessary for this example
throw new Error("not implemented");
case Token.BINARY:
size = readVarint32();
pson.onBinary(offset, size);
offset += size;
break;
default: // small integer?
if (token > Token.MAX)
throw new Error("unexpected token");
pson.onInteger((token >> 1) ^ -(token & 1));
break;
}
}
function readVarint32(): u32 {
var value: u32 = 0;
var shift: u32 = 0;
do {
var b = load<u8>(offset++);
value |= <u32>(b & 0x7f) << (7 * shift++);
} while (b & 0x80);
return value;
}
function readVarint64(): u64 {
var value: u64 = 0;
var shift: u64 = 0;
do {
var b = load<u8>(offset++);
value |= <u64>(b & 0x7f) << (7 * shift++);
} while (b & 0x80);
return value;
}

View File

@ -0,0 +1,6 @@
{
"extends": "../../../std/assembly.json",
"include": [
"./**/*.ts"
]
}

71
examples/pson/index.js Normal file
View File

@ -0,0 +1,71 @@
var fs = require("fs");
// Define imports. Just logs to console for the sake of this example.
var pson = {
onNull: function() {
console.log("null");
},
onTrue: function() {
console.log("true");
},
onFalse: function() {
console.log("false");
},
onEObject: function() {
console.log("{}");
},
onEArray: function() {
console.log("[]");
},
onEString: function() {
console.log("\"\"");
},
onObject: function(size) {
console.log("{" + size + "}")
},
onArray: function(size) {
console.log("[" + size + "]");
},
onInteger: function(value) {
console.log("integer: " + value);
},
onLong: function(valueLow, valueHigh) {
console.log("long: " + valueLow + ", " + valueHigh);
},
onFloat: function(value) {
console.log("float: " + value);
},
onDouble: function(value) {
console.log("double: " + value);
},
onString: function(offset, length) {
console.log("string(length=" + length + "): " + new Buffer(mem.slice(offset, offset + length)).toString());
},
onBinary: function(offset, length) {
console.log("binary(length=" + length + "): " + mem.slice(offset, offset + length));
},
onTruncated: function() {
console.log("buffer is truncated :-(");
}
};
// Instantiate the module
var mod = new WebAssembly.Module(fs.readFileSync(__dirname + "/pson.optimized.wasm"));
var ins = new WebAssembly.Instance(mod, { pson: pson });
var mem = new Uint8Array(ins.exports.memory.buffer);
// Export API
exports.decode = function(buffer) {
// grow memory if necessary
if (mem.length < buffer.length) {
ins.exports.memory.grow(Math.ceil((buffer.length - mem.length) / 65536));
mem = new Uint8Array(ins.exports.memory.buffer);
}
// copy buffer to memory
mem.set(buffer);
// start decoding (calls the imports defined above)
ins.exports.decode(buffer.length);
}

View File

@ -0,0 +1,14 @@
{
"name": "@assemblyscript/pson-example",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "asc assembly/pson.ts -b pson.untouched.wasm -t pson.untouched.wast --validate",
"build:optimized": "asc -O assembly/pson.ts -b pson.optimized.wasm -t pson.optimized.wast --validate",
"test": "node tests"
},
"devDependencies": {
"pson": "^2.0.0"
}
}

View File

@ -0,0 +1,24 @@
var Long = require("long");
var psonJS = require("pson");
var psonWASM = require("..");
// encode in JS
var buf = new psonJS.Encoder().encode({
emptyObject: {},
emptyArray: [],
emptyString: "",
object: {
aSmallInt: 42,
anInt: 9000,
aLong: Long.MIN_VALUE.add(1)
},
array: [
0.25, // fits into float
0.1 // always a double
],
binary: Buffer.from([1, 2, 3])
}).toBuffer();
// decode in WASM
psonWASM.decode(buf);

View File

@ -2182,7 +2182,7 @@ function builderEndsWith(sb: string[], code: CharCode): bool {
}
/** Converts a string to its literal representation including quotes. */
export function stringToLiteral(str: string): string {
export function stringToLiteral(str: string, singleQuoted: bool = false): string {
var ret = new Array<string>();
var off = 0;
for (var i = 0, k = str.length; i < k;) {
@ -2263,11 +2263,12 @@ export function stringToLiteral(str: string): string {
break;
}
}
var quote = singleQuoted ? "'" : "\"";
if (off == 0) {
assert(ret.length == 0);
return "\"" + str + "\"";
return quote + str + quote;
}
if (i > off)
ret.push(str.substring(off, i));
return "\"" + ret.join("") + "\"";
return quote + ret.join("") + quote;
}

View File

@ -840,8 +840,8 @@ export class Compiler extends DiagnosticEmitter {
compileDoStatement(statement: DoStatement): ExpressionRef {
var label = this.currentFunction.enterBreakContext();
var condition = this.compileExpression(statement.condition, Type.i32);
var body = this.compileStatement(statement.statement);
var condition = this.compileExpression(statement.condition, Type.i32);
this.currentFunction.leaveBreakContext();
var breakLabel = "break|" + label;
var continueLabel = "continue|" + label;
@ -1494,8 +1494,11 @@ export class Compiler extends DiagnosticEmitter {
case Token.PERCENT:
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
if (this.currentType.isAnyFloat)
throw new Error("not implemented"); // TODO: internal fmod, possibly simply imported from JS
if (this.currentType.isAnyFloat) {
// TODO: internal fmod, possibly simply imported from JS
this.error(DiagnosticCode.Operation_not_supported, expression.range);
return this.module.createUnreachable();
}
op = this.currentType.isSignedInteger
? this.currentType.isLongInteger
? BinaryOp.RemI64

View File

@ -796,7 +796,7 @@ export class Module {
}
// currently supports side effect free expressions only
cloneExpression(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = 0x7fffffff): ExpressionRef {
cloneExpression(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = i32.MAX_VALUE): ExpressionRef {
if (this.noEmit || maxDepth < 0) return 0;
var nested1: ExpressionRef,
@ -900,28 +900,24 @@ export class Relooper {
}
}
export function setAPITracing(on: bool): void {
_BinaryenSetAPITracing(on ? 1 : 0);
}
// helpers
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js
function allocU8Array(u8s: Uint8Array | null): usize {
if (!u8s) return 0;
var ptr = Heap.allocate((<Uint8Array>u8s).length);
var ptr = Heap.allocate(u8s.length);
var idx = ptr;
for (var i = 0, k = (<Uint8Array>u8s).length; i < k; ++i)
store<u8>(idx++, (<Uint8Array>u8s)[i]);
for (var i = 0, k = u8s.length; i < k; ++i)
store<u8>(idx++, u8s[i]);
return ptr;
}
function allocI32Array(i32s: i32[] | null): usize {
if (!i32s) return 0;
var ptr = Heap.allocate((<i32[]>i32s).length << 2);
var ptr = Heap.allocate(i32s.length << 2);
var idx = ptr;
for (var i = 0, k = (<i32[]>i32s).length; i < k; ++i) {
var val = (<i32[]>i32s)[i];
for (var i = 0, k = i32s.length; i < k; ++i) {
var val = i32s[i];
// store<i32>(idx, val) is not portable
store<u8>(idx , ( val & 0xff) as u8);
store<u8>(idx + 1, ((val >> 8) & 0xff) as u8);
@ -956,12 +952,12 @@ function stringLengthUTF8(str: string): usize {
function allocString(str: string | null): usize {
if (str == null) return 0;
var ptr = Heap.allocate(stringLengthUTF8((<string>str)) + 1);
var ptr = Heap.allocate(stringLengthUTF8(str) + 1);
var idx = ptr;
for (var i = 0, k = (<string>str).length; i < k; ++i) {
var u = (<string>str).charCodeAt(i);
for (var i = 0, k = str.length; i < k; ++i) {
var u = str.charCodeAt(i);
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
u = 0x10000 + ((u & 0x3FF) << 10) | ((<string>str).charCodeAt(++i) & 0x3FF);
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
if (u <= 0x7F)
store<u8>(idx++, u as u8);
else if (u <= 0x7FF) {

View File

@ -1 +1,3 @@
assert(true);
assert(1 == 1);
assert(0.5 > 0.4);

View File

@ -11,6 +11,24 @@
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(i32.const 1)
(i32.const 1)
)
)
(unreachable)
)
(if
(i32.eqz
(f64.gt
(f64.const 0.5)
(f64.const 0.4)
)
)
(unreachable)
)
)
)
(;

View File

@ -1,6 +1,6 @@
let b: bool = false;
var b = false;
let i: i32 = 0;
var i: i32 = 0;
i < 1;
i > 1;
@ -49,7 +49,7 @@ i &= 1;
i |= 1;
i ^= 1;
let I: i64 = 0;
var I: i64 = 0;
I < 1;
I > 1;
@ -98,7 +98,7 @@ I &= 1;
I |= 1;
I ^= 1;
let f: f32 = 0;
var f: f32 = 0;
f < 1;
f > 1;
@ -129,7 +129,7 @@ f -= 1;
f *= 1;
// f %= 1;
let F: f64 = 0;
var F: f64 = 0;
F < 1;
F > 1;

View File

@ -7,9 +7,13 @@
(global $builtins/F (mut f64) (f64.const 0))
(global $builtins/s (mut i32) (i32.const 0))
(memory $0 1)
(export "test" (func $builtins/test))
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(func $builtins/test (; 0 ;) (type $v)
(nop)
)
(func $start (; 1 ;) (type $v)
(local $0 f32)
(local $1 f64)
(local $2 i32)

View File

@ -1,8 +1,8 @@
let b: bool;
var b: bool;
// integers
let i: i32;
var i: i32;
clz<i32>(1);
ctz<i32>(1);
@ -22,7 +22,7 @@ i = abs<i32>(-42); assert(i == 42);
i = max<i32>(1, 2); assert(i == 2);
i = min<i32>(1, 2); assert(i == 1);
let I: i64;
var I: i64;
clz<i64>(1);
ctz<i64>(1);
@ -42,7 +42,7 @@ I = min<i64>(1, 2); assert(i == 1);
// floats
let f: f32;
var f: f32;
<f32>NaN;
<f32>Infinity;
@ -72,7 +72,7 @@ f = trunc<f32>(1.25);
b = isNaN<f32>(1.25);
b = isFinite<f32>(1.25);
let F: f64;
var F: f64;
<f64>NaN;
<f64>Infinity;
@ -129,7 +129,7 @@ F = reinterpret<i64,f64>(25);
// host
let s: usize;
var s: usize;
current_memory();
grow_memory(1);
@ -179,8 +179,9 @@ assert(isFinite<f64>(0));
// imported
// TODO: Can't be interpreted due to 'Fatal: callImport: unknown import: env.parseInt'
// parseInt(0);
// parseInt(0, 10);
// parseFloat(0);
export function test(): void {
// cannot be interpreted
// parseInt("01");
// parseInt("1", 10);
// parseFloat("1.0");
}

View File

@ -8,9 +8,12 @@
(global $builtins/s (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "test" (func $builtins/test))
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(func $builtins/test (; 0 ;) (type $v)
)
(func $start (; 1 ;) (type $v)
(local $0 i32)
(local $1 i32)
(local $2 i64)
@ -1085,6 +1088,7 @@
GLOBAL: builtins/f
GLOBAL: builtins/F
GLOBAL: builtins/s
FUNCTION_PROTOTYPE: builtins/test
[program.exports]
FUNCTION_PROTOTYPE: builtins/test
;)

View File

@ -1,42 +1,132 @@
(module
(type $iv (func (param i32)))
(type $v (func))
(global $do/n (mut i32) (i32.const 10))
(global $do/m (mut i32) (i32.const 0))
(global $do/o (mut i32) (i32.const 0))
(memory $0 1)
(export "loopDo" (func $do/loopDo))
(export "loopDoInDo" (func $do/loopDoInDo))
(export "memory" (memory $0))
(func $do/loopDo (; 0 ;) (type $iv) (param $0 i32)
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(loop $continue|0
(set_global $do/n
(i32.sub
(get_global $do/n)
(i32.const 1)
)
)
(set_global $do/m
(i32.add
(get_global $do/m)
(i32.const 1)
)
)
(br_if $continue|0
(tee_local $0
(i32.sub
(get_local $0)
(i32.const 1)
(get_global $do/n)
)
)
(if
(get_global $do/n)
(unreachable)
)
(if
(i32.ne
(get_global $do/m)
(i32.const 10)
)
(unreachable)
)
(func $do/loopDoInDo (; 1 ;) (type $iv) (param $0 i32)
(loop $continue|0
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
(set_global $do/n
(i32.const 10)
)
(loop $continue|1
(br_if $continue|1
(tee_local $0
(set_global $do/n
(i32.sub
(get_local $0)
(tee_local $0
(get_global $do/n)
)
(i32.const 1)
)
)
)
)
(br_if $continue|0
(br_if $continue|1
(get_local $0)
)
)
(if
(i32.ne
(get_global $do/n)
(i32.const -1)
)
(unreachable)
)
(set_global $do/n
(i32.const 10)
)
(set_global $do/m
(i32.const 0)
)
(loop $continue|2
(set_global $do/n
(i32.sub
(get_global $do/n)
(i32.const 1)
)
)
(set_global $do/m
(i32.add
(get_global $do/m)
(i32.const 1)
)
)
(loop $continue|3
(set_global $do/n
(i32.sub
(get_global $do/n)
(i32.const 1)
)
)
(set_global $do/o
(i32.add
(get_global $do/o)
(i32.const 1)
)
)
(br_if $continue|3
(get_global $do/n)
)
)
(if
(get_global $do/n)
(unreachable)
)
(if
(i32.ne
(get_global $do/o)
(i32.const 9)
)
(unreachable)
)
(br_if $continue|2
(get_global $do/n)
)
)
(if
(get_global $do/n)
(unreachable)
)
(if
(i32.ne
(get_global $do/m)
(i32.const 1)
)
(unreachable)
)
(if
(i32.ne
(get_global $do/o)
(i32.const 9)
)
(unreachable)
)
)
)

View File

@ -1,14 +1,29 @@
export function loopDo(n: i32): void {
var n = 10;
var m = 0;
do {
n = n - 1;
n--;
m++;
} while (n);
}
assert(n == 0);
assert(m == 10);
export function loopDoInDo(n: i32): void {
n = 10;
do; while(n--);
assert(n == -1);
n = 10;
m = 0;
var o = 0;
do {
n = n - 1;
n--;
m++;
do {
n = n - 1;
n--;
o++;
} while (n);
assert(n == 0);
assert(o == 9);
} while (n);
}
assert(n == 0);
assert(m == 1);
assert(o == 9);

View File

@ -1,55 +1,229 @@
(module
(type $iv (func (param i32)))
(type $v (func))
(global $do/n (mut i32) (i32.const 10))
(global $do/m (mut i32) (i32.const 0))
(global $do/o (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "loopDo" (func $do/loopDo))
(export "loopDoInDo" (func $do/loopDoInDo))
(export "memory" (memory $0))
(func $do/loopDo (; 0 ;) (type $iv) (param $0 i32)
(block $break|0
(loop $continue|0
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(br_if $continue|0
(get_local $0)
)
)
)
)
(func $do/loopDoInDo (; 1 ;) (type $iv) (param $0 i32)
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(block $break|0
(loop $continue|0
(block
(drop
(block (result i32)
(set_local $0
(get_global $do/n)
)
(set_global $do/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(block $break|1
(loop $continue|1
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(i32.sub
(get_global $do/m)
)
(set_global $do/m
(i32.add
(get_local $0)
(i32.const 1)
)
)
(br_if $continue|1
(get_local $0)
)
)
)
)
(br_if $continue|0
(get_global $do/n)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $do/n)
(i32.const 0)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $do/m)
(i32.const 10)
)
)
(unreachable)
)
(set_global $do/n
(i32.const 10)
)
(block $break|1
(loop $continue|1
(nop)
(br_if $continue|1
(block (result i32)
(set_local $0
(get_global $do/n)
)
(set_global $do/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $do/n)
(i32.sub
(i32.const 0)
(i32.const 1)
)
)
)
(unreachable)
)
(set_global $do/n
(i32.const 10)
)
(set_global $do/m
(i32.const 0)
)
(block $break|2
(loop $continue|2
(block
(drop
(block (result i32)
(set_local $0
(get_global $do/n)
)
(set_global $do/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(get_global $do/m)
)
(set_global $do/m
(i32.add
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(block $break|3
(loop $continue|3
(block
(drop
(block (result i32)
(set_local $0
(get_global $do/n)
)
(set_global $do/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(get_global $do/o)
)
(set_global $do/o
(i32.add
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
)
(br_if $continue|3
(get_global $do/n)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $do/n)
(i32.const 0)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $do/o)
(i32.const 9)
)
)
(unreachable)
)
)
(br_if $continue|2
(get_global $do/n)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $do/n)
(i32.const 0)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $do/m)
(i32.const 1)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $do/o)
(i32.const 9)
)
)
(unreachable)
)
)
)
(;
[program.elements]
@ -97,9 +271,9 @@
FUNCTION_PROTOTYPE: isize
FUNCTION_PROTOTYPE: usize
GLOBAL: HEAP_BASE
FUNCTION_PROTOTYPE: do/loopDo
FUNCTION_PROTOTYPE: do/loopDoInDo
GLOBAL: do/n
GLOBAL: do/m
GLOBAL: do/o
[program.exports]
FUNCTION_PROTOTYPE: do/loopDo
FUNCTION_PROTOTYPE: do/loopDoInDo
;)

View File

@ -10,6 +10,7 @@
(export "renamed_b" (global $export/b))
(export "two" (func $export/ns.two))
(export "memory" (memory $0))
(start $export/ns.two)
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(get_local $0)

View File

@ -11,6 +11,7 @@ export { sub as renamed_sub };
export const a: i32 = 1;
const b: i32 = 2;
b;
export { b as renamed_b };

View File

@ -11,6 +11,7 @@
(export "renamed_b" (global $export/b))
(export "two" (func $export/ns.two))
(export "memory" (memory $0))
(start $start)
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(i32.add
@ -29,6 +30,11 @@
)
(func $export/ns.two (; 2 ;) (type $v)
)
(func $start (; 3 ;) (type $v)
(drop
(i32.const 2)
)
)
)
(;
[program.elements]

View File

@ -1,10 +1,10 @@
let i: i32;
var i: i32;
for (i = 0; i < 10; ++i) {
;
}
assert(i == 10);
for (let j: i32 = 0; j < 10; ++j) {
for (var j: i32 = 0; j < 10; ++j) {
;
}

View File

@ -33,105 +33,105 @@
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 i32)
(local $10 i32)
(nop)
(nop)
(block
(set_local $6
(set_local $0
(i32.sub
(get_global $../../examples/game-of-life/assembly/game-of-life/h)
(i32.const 1)
)
)
(set_local $7
(set_local $1
(i32.sub
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
(i32.const 1)
)
)
)
(block
(set_local $10
(i32.const 0)
)
)
(block $break|0
(set_local $0
(block
(set_local $2
(i32.const 0)
)
)
(loop $continue|0
(if
(i32.lt_u
(get_local $0)
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/h)
)
(block
(block
(set_local $1
(block
(set_local $3
(select
(get_local $6)
(i32.sub
(get_local $0)
(i32.sub
(get_local $2)
(i32.const 1)
)
(i32.eq
(get_local $0)
(get_local $2)
(i32.const 0)
)
)
)
(set_local $2
(set_local $4
(select
(i32.const 0)
(i32.add
(get_local $0)
(get_local $2)
(i32.const 1)
)
(i32.eq
(get_local $2)
(get_local $0)
(get_local $6)
)
)
)
)
(block $break|1
(set_local $3
(block
(set_local $5
(i32.const 0)
)
)
(loop $continue|1
(if
(i32.lt_u
(get_local $3)
(get_local $5)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(block
(block
(set_local $4
(block
(set_local $6
(select
(get_local $7)
(get_local $1)
(i32.sub
(get_local $3)
(get_local $5)
(i32.const 1)
)
(i32.eq
(get_local $3)
(get_local $5)
(i32.const 0)
)
)
)
(set_local $5
(set_local $7
(select
(i32.const 0)
(i32.add
(get_local $3)
(get_local $5)
(i32.const 1)
)
(i32.eq
(get_local $3)
(get_local $7)
(get_local $5)
(get_local $1)
)
)
)
)
(block
(set_local $8
(i32.add
(i32.add
@ -143,26 +143,16 @@
(i32.load8_u
(i32.add
(i32.mul
(get_local $1)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $4)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $1)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $6)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $1)
(get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $5)
@ -172,17 +162,47 @@
(i32.load8_u
(i32.add
(i32.mul
(get_local $0)
(get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $4)
(get_local $7)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $0)
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $6)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $7)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $4)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $6)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $4)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $5)
@ -192,47 +212,25 @@
(i32.load8_u
(i32.add
(i32.mul
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $4)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $3)
(get_local $7)
)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $5)
)
)
)
)
(set_local $9
(i32.load8_u
(i32.add
(i32.mul
(get_local $0)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $3)
)
)
)
(if
(get_local $9)
(i32.load8_u
(i32.add
(i32.mul
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $5)
)
)
(if
(if (result i32)
(i32.lt_u
@ -253,11 +251,11 @@
(i32.add
(get_global $../../examples/game-of-life/assembly/game-of-life/s)
(i32.mul
(get_local $0)
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
)
(get_local $3)
(get_local $5)
)
(i32.const 0)
)
@ -272,20 +270,20 @@
(i32.add
(get_global $../../examples/game-of-life/assembly/game-of-life/s)
(i32.mul
(get_local $0)
(get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
)
(get_local $3)
(get_local $5)
)
(i32.const 1)
)
)
)
)
(set_local $3
(set_local $5
(i32.add
(get_local $3)
(get_local $5)
(i32.const 1)
)
)
@ -295,9 +293,9 @@
)
)
)
(set_local $0
(set_local $2
(i32.add
(get_local $0)
(get_local $2)
(i32.const 1)
)
)

View File

@ -1,8 +1,8 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $export/a i32 (i32.const 1))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "memory" (memory $0))
@ -26,6 +26,9 @@
(func $export/ns.two (; 2 ;) (type $v)
)
(func $start (; 3 ;) (type $v)
(drop
(i32.const 2)
)
(drop
(i32.add
(call $export/add

View File

@ -8,39 +8,39 @@ const F = 1.5;
F;
function locals(): void {
let li = 10;
let lI = 0x100000000;
let lF = 1.5;
let ai = i;
let aI = I;
let aF = F;
var li = 10;
var lI = 0x100000000;
var lF = 1.5;
var ai = i;
var aI = I;
var aF = F;
}
locals();
function reti(): i32 {
return 0;
}
let ri = reti();
var ri = reti();
ri;
function retI(): i64 {
return 0;
}
let rI = retI();
var rI = retI();
rI;
function retf(): f32 {
return 0;
}
let rf = retf();
var rf = retf();
rf;
function refF(): f64 {
return 0;
}
let rF = refF();
var rF = refF();
rF;
for (let a = 0, b = 10; a < b; ++a) {
for (var a = 0, b = 10; a < b; ++a) {
;
}

View File

@ -6,7 +6,7 @@
1 && 2 || unreachable();
1.0 && 2.0 || unreachable();
let i: i32;
var i: i32;
i = 1 && 2;
assert(i == 2);
@ -14,7 +14,7 @@ assert(i == 2);
i = 0 || 1;
assert(i == 1);
let I: i64;
var I: i64;
I = 1 && 2;
assert(I == 2);
@ -22,7 +22,7 @@ assert(I == 2);
I = 0 || 1;
assert(I == 1);
let f: f32;
var f: f32;
f = 1.0 && 2.0;
assert(f == 2.0);
@ -30,7 +30,7 @@ assert(f == 2.0);
f = 0.0 || 1.0;
assert(f == 1.0);
let F: f64;
var F: f64;
F = 1.0 && 2.0;
assert(F == 2.0);

View File

@ -1,7 +1,7 @@
export function memcpy(dest: usize, src: usize, n: usize): usize {
// the following is based on musl's implementation of memcpy
let d: usize = dest, s: usize = src;
let w: u32, x: u32;
var d: usize = dest, s: usize = src;
var w: u32, x: u32;
// copy 1 byte each until src is aligned to 4 bytes
while (n && s % 4) {
@ -147,7 +147,7 @@ store<u64>(base + 8 , 0x2222222222222222);
store<u64>(base + 16, 0x3333333333333333);
store<u64>(base + 24, 0x4444444444444444);
let dest: usize;
var dest: usize;
dest = memcpy(base + 1, base + 16, 4);
assert(dest == base + 1);
assert(load<u64>(base) == 0x1111113333333311);

View File

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

View File

@ -1,7 +1,7 @@
let i: i32 = 0;
let I: i64 = 0;
let f: f32 = 0;
let F: f64 = 0;
var i: i32 = 0;
var I: i64 = 0;
var f: f32 = 0;
var F: f64 = 0;
i8(i);
i8(I);

View File

@ -1,8 +1,8 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $export/a i32 (i32.const 1))
(memory $0 1)
(export "add" (func $export/add))
(export "renamed_sub" (func $export/sub))

View File

@ -1,8 +1,8 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $export/a i32 (i32.const 1))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "add" (func $export/add))
@ -32,6 +32,9 @@
(func $export/ns.two (; 2 ;) (type $v)
)
(func $start (; 3 ;) (type $v)
(drop
(i32.const 2)
)
(drop
(i32.add
(call $export/add

View File

@ -2,7 +2,7 @@
1 ? 1 : unreachable();
(0 ? unreachable() : 1) ? 1 : unreachable();
let a: i32;
var a: i32;
a = 0 ? unreachable() : 1;
a = 1 ? 1 : unreachable();

View File

@ -180,9 +180,9 @@ export function control$construct(ptr: usize): void {
block$set_next_free(ptr, ptr);
block$set_prev_free(ptr, ptr);
control$set_fl_bitmap(ptr, 0);
for (let flIndex: usize = 0; flIndex < FL_INDEX_COUNT; ++flIndex) {
for (var flIndex: usize = 0; flIndex < FL_INDEX_COUNT; ++flIndex) {
control$set_sl_bitmap(ptr, flIndex, 0);
for (let slIndex: usize = 0; slIndex < SL_INDEX_COUNT; ++slIndex)
for (var slIndex: usize = 0; slIndex < SL_INDEX_COUNT; ++slIndex)
control$set_block(ptr, flIndex, slIndex, ptr);
}
}

View File

@ -6,7 +6,7 @@
-1.25;
!1.25;
let i: i32 = 0;
var i: i32 = 0;
+i;
-i;
@ -30,7 +30,7 @@ i = --i;
i = i++;
i = i--;
let I: i64 = 0;
var I: i64 = 0;
+I;
-I;
@ -54,7 +54,7 @@ I = --I;
I = I++;
I = I--;
let f: f32 = 0;
var f: f32 = 0;
+f;
-f;
@ -75,7 +75,7 @@ f = --f;
f = f++;
f = f--;
let F: f64 = 0;
var F: f64 = 0;
+F;
-F;

View File

@ -1,17 +1,26 @@
(module
(type $iv (func (param i32)))
(type $v (func))
(global $while/n (mut i32) (i32.const 10))
(global $while/m (mut i32) (i32.const 0))
(global $while/o (mut i32) (i32.const 0))
(memory $0 1)
(export "loopWhile" (func $while/loopWhile))
(export "loopWhileInWhile" (func $while/loopWhileInWhile))
(export "memory" (memory $0))
(func $while/loopWhile (; 0 ;) (type $iv) (param $0 i32)
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(loop $continue|0
(if
(get_local $0)
(get_global $while/n)
(block
(set_local $0
(set_global $while/n
(i32.sub
(get_local $0)
(get_global $while/n)
(i32.const 1)
)
)
(set_global $while/m
(i32.add
(get_global $while/m)
(i32.const 1)
)
)
@ -19,35 +28,140 @@
)
)
)
)
(func $while/loopWhileInWhile (; 1 ;) (type $iv) (param $0 i32)
(loop $continue|0
(if
(get_local $0)
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
(get_global $while/n)
(unreachable)
)
(if
(i32.ne
(get_global $while/m)
(i32.const 10)
)
(unreachable)
)
(set_global $while/n
(i32.const 10)
)
(set_global $while/m
(i32.const 0)
)
(loop $continue|1
(if
(get_local $0)
(get_global $while/n)
(block
(set_local $0
(set_global $while/n
(i32.sub
(get_local $0)
(get_global $while/n)
(i32.const 1)
)
)
(set_global $while/m
(i32.add
(get_global $while/m)
(i32.const 1)
)
)
(loop $continue|2
(if
(get_global $while/n)
(block
(set_global $while/n
(i32.sub
(get_global $while/n)
(i32.const 1)
)
)
(set_global $while/o
(i32.add
(get_global $while/o)
(i32.const 1)
)
)
(br $continue|2)
)
)
)
(if
(get_global $while/n)
(unreachable)
)
(if
(i32.ne
(get_global $while/o)
(i32.const 9)
)
(unreachable)
)
(br $continue|1)
)
)
)
(br $continue|0)
(if
(get_global $while/n)
(unreachable)
)
(if
(i32.ne
(get_global $while/m)
(i32.const 1)
)
(unreachable)
)
(if
(i32.ne
(get_global $while/o)
(i32.const 9)
)
(unreachable)
)
(set_global $while/n
(i32.const 1)
)
(set_global $while/m
(i32.const 0)
)
(loop $continue|3
(br_if $continue|3
(if (result i32)
(block (result i32)
(set_global $while/n
(i32.sub
(tee_local $0
(get_global $while/n)
)
(i32.const 1)
)
)
(tee_local $0
(get_local $0)
)
)
(block (result i32)
(set_global $while/m
(i32.add
(get_global $while/m)
(i32.const 1)
)
)
(get_global $while/m)
)
(get_local $0)
)
)
)
(if
(i32.ne
(get_global $while/n)
(i32.const -1)
)
(unreachable)
)
(if
(i32.ne
(get_global $while/m)
(i32.const 1)
)
(unreachable)
)
)
)

View File

@ -1,14 +1,32 @@
export function loopWhile(n: i32): void {
while (n) {
n = n - 1;
}
}
var n = 10;
var m = 0;
export function loopWhileInWhile(n: i32): void {
while (n) {
n = n - 1;
n--;
m++;
}
assert(n == 0);
assert(m == 10);
n = 10;
m = 0;
var o = 0;
while (n) {
n = n - 1;
}
n--;
m++;
while (n) {
n--;
o++;
}
assert(n == 0);
assert(o == 9);
}
assert(n == 0);
assert(m == 1);
assert(o == 9);
n = 1;
m = 0;
while (n-- && ++m);
assert(n == -1);
assert(m == 1);

View File

@ -1,63 +1,266 @@
(module
(type $iv (func (param i32)))
(type $v (func))
(global $while/n (mut i32) (i32.const 10))
(global $while/m (mut i32) (i32.const 0))
(global $while/o (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "loopWhile" (func $while/loopWhile))
(export "loopWhileInWhile" (func $while/loopWhileInWhile))
(export "memory" (memory $0))
(func $while/loopWhile (; 0 ;) (type $iv) (param $0 i32)
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(block $break|0
(loop $continue|0
(if
(get_local $0)
(get_global $while/n)
(block
(block
(drop
(block (result i32)
(set_local $0
(get_global $while/n)
)
(set_global $while/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(get_global $while/m)
)
(set_global $while/m
(i32.add
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
)
(br $continue|0)
)
)
)
)
)
(func $while/loopWhileInWhile (; 1 ;) (type $iv) (param $0 i32)
(block $break|0
(loop $continue|0
(if
(get_local $0)
(block
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
(i32.eqz
(i32.eq
(get_global $while/n)
(i32.const 0)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $while/m)
(i32.const 10)
)
)
(unreachable)
)
(set_global $while/n
(i32.const 10)
)
(set_global $while/m
(i32.const 0)
)
(block $break|1
(loop $continue|1
(if
(get_local $0)
(get_global $while/n)
(block
(block
(drop
(block (result i32)
(set_local $0
(get_global $while/n)
)
(set_global $while/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(get_global $while/m)
)
(set_global $while/m
(i32.add
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(block $break|2
(loop $continue|2
(if
(get_global $while/n)
(block
(block
(drop
(block (result i32)
(set_local $0
(get_global $while/n)
)
(set_global $while/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(drop
(block (result i32)
(set_local $0
(get_global $while/o)
)
(set_global $while/o
(i32.add
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
)
(br $continue|2)
)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $while/n)
(i32.const 0)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $while/o)
(i32.const 9)
)
)
(unreachable)
)
)
(br $continue|1)
)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $while/n)
(i32.const 0)
)
(br $continue|0)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $while/m)
(i32.const 1)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $while/o)
(i32.const 9)
)
)
(unreachable)
)
(set_global $while/n
(i32.const 1)
)
(set_global $while/m
(i32.const 0)
)
(block $break|3
(loop $continue|3
(if
(if (result i32)
(tee_local $0
(block (result i32)
(set_local $0
(get_global $while/n)
)
(set_global $while/n
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(get_local $0)
)
)
(block (result i32)
(set_global $while/m
(i32.add
(get_global $while/m)
(i32.const 1)
)
)
(get_global $while/m)
)
(get_local $0)
)
(block
(nop)
(br $continue|3)
)
)
)
)
(if
(i32.eqz
(i32.eq
(get_global $while/n)
(i32.sub
(i32.const 0)
(i32.const 1)
)
)
)
(unreachable)
)
(if
(i32.eqz
(i32.eq
(get_global $while/m)
(i32.const 1)
)
)
(unreachable)
)
)
)
(;
@ -106,9 +309,9 @@
FUNCTION_PROTOTYPE: isize
FUNCTION_PROTOTYPE: usize
GLOBAL: HEAP_BASE
FUNCTION_PROTOTYPE: while/loopWhile
FUNCTION_PROTOTYPE: while/loopWhileInWhile
GLOBAL: while/n
GLOBAL: while/m
GLOBAL: while/o
[program.exports]
FUNCTION_PROTOTYPE: while/loopWhile
FUNCTION_PROTOTYPE: while/loopWhileInWhile
;)