Skip to content

Commit 2888ba1

Browse files
committed
PSON decoder example using namespaced imports
1 parent c67f87a commit 2888ba1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1263
-316
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
[![Build Status](https://travis-ci.org/AssemblyScript/assemblyscript.svg?branch=master)](https://travis-ci.org/AssemblyScript/assemblyscript)
55

6-
**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.
6+
**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.
77

88
Examples
99
--------
@@ -16,6 +16,9 @@ A few early examples to get an idea:
1616
* **[i64 polyfill](./examples/i64-polyfill)**<br />
1717
Exposes WebAssembly's i64 operations to JavaScript using 32-bit integers (low and high bits).
1818

19+
* **[PSON decoder](./examples/pson)**<br />
20+
A PSON decoder implemented in AssemblyScript.
21+
1922
Or browse the [compiler tests](./tests/compiler) for a more in-depth overview of what's supported already.
2023

2124
Getting started

examples/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
*.wast
22
*.wasm
33
node_modules/
4+
npm-debug.log
5+
package-lock.json

examples/game-of-life/assembly/game-of-life.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// A simplified version of the game of life as seen on http://dcode.io
22

3-
var w: u32; // width
4-
var h: u32; // height
5-
var s: u32; // total size
3+
var w: u32, // width
4+
h: u32, // height
5+
s: u32; // total size
66

77
/** Initializes width and height. */
88
export function init(w_: u32, h_: u32): void {
@@ -13,21 +13,18 @@ export function init(w_: u32, h_: u32): void {
1313

1414
/** Performs one step. */
1515
export function step(): void {
16-
var y: u32, ym1: u32, yp1: u32; // y, y-1 and y+1
17-
var x: u32, xm1: u32, xp1: u32; // x, x-1 and x+1
18-
var hm1: u32 = h - 1, wm1: u32 = w - 1;
19-
var n: u32, v: u8, c: u32 = 0;
20-
for (y = 0; y < h; ++y) {
21-
ym1 = select<u32>(hm1, y - 1, y == 0);
22-
yp1 = select<u32>(0, y + 1, y == hm1);
23-
for (x = 0; x < w; ++x) {
24-
xm1 = select<u32>(wm1, x - 1, x == 0);
25-
xp1 = select<u32>(0, x + 1, x == wm1);
26-
n = load<u8>(ym1 * w + xm1) + load<u8>(ym1 * w + x) + load<u8>(ym1 * w + xp1)
27-
+ load<u8>(y * w + xm1) + load<u8>(y * w + xp1)
28-
+ load<u8>(yp1 * w + xm1) + load<u8>(yp1 * w + x) + load<u8>(yp1 * w + xp1);
29-
v = load<u8>(y * w + x);
30-
if (v) {
16+
var hm1 = h - 1,
17+
wm1 = w - 1;
18+
for (var y: u32 = 0; y < h; ++y) {
19+
var ym1 = select<u32>(hm1, y - 1, y == 0),
20+
yp1 = select<u32>(0, y + 1, y == hm1);
21+
for (var x: u32 = 0; x < w; ++x) {
22+
var xm1 = select<u32>(wm1, x - 1, x == 0),
23+
xp1 = select<u32>(0, x + 1, x == wm1);
24+
var n = load<u8>(ym1 * w + xm1) + load<u8>(ym1 * w + x) + load<u8>(ym1 * w + xp1)
25+
+ load<u8>(y * w + xm1) + load<u8>(y * w + xp1)
26+
+ load<u8>(yp1 * w + xm1) + load<u8>(yp1 * w + x) + load<u8>(yp1 * w + xp1);
27+
if (load<u8>(y * w + x)) {
3128
if (n < 2 || n > 3)
3229
store<u8>(s + y * w + x, 0);
3330
} else if (n == 3)

examples/i64-polyfill/assembly/i64.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
let lo: u32;
2-
let hi: u32;
1+
var lo: u32,
2+
hi: u32;
33

44
export function getLo(): u32 {
55
return lo;

examples/pson/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
PSON decoder in WebAssembly
2+
===========================
3+
4+
An [AssemblyScript](http://assemblyscript.org) example. Decodes a [PSON](https://github.com/dcodeIO/PSON) encoded buffer.
5+
6+
Instructions
7+
------------
8+
9+
To build [assembly/pson.ts](./assembly/pson.ts) to an untouched and an optimized `.wasm` including their respective `.wast` representations, run:
10+
11+
```
12+
$> npm run build
13+
```
14+
15+
Afterwards, to run the included test, do:
16+
17+
```
18+
$> npm test
19+
```

examples/pson/assembly/pson.ts

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
const enum Token {
2+
ZERO = 0x00,
3+
MAX = 0xEF,
4+
NULL = 0xf0,
5+
TRUE = 0xf1,
6+
FALSE = 0xf2,
7+
EOBJECT = 0xf3,
8+
EARRAY = 0xf4,
9+
ESTRING = 0xf5,
10+
OBJECT = 0xf6,
11+
ARRAY = 0xf7,
12+
INTEGER = 0xf8,
13+
LONG = 0xf9,
14+
FLOAT = 0xfa,
15+
DOUBLE = 0xfb,
16+
STRING = 0xfc,
17+
STRING_ADD = 0xfd,
18+
STRING_GET = 0xfe,
19+
BINARY = 0xff
20+
}
21+
22+
namespace pson {
23+
export declare function onNull(): void;
24+
export declare function onTrue(): void;
25+
export declare function onFalse(): void;
26+
export declare function onEObject(): void;
27+
export declare function onEArray(): void;
28+
export declare function onEString(): void;
29+
export declare function onObject(size: u32): void;
30+
export declare function onArray(size: u32): void;
31+
export declare function onInteger(value: i32): void;
32+
export declare function onLong(valueLow: i32, valueHigh: i32): void;
33+
export declare function onFloat(value: f32): void;
34+
export declare function onDouble(value: f64): void;
35+
export declare function onString(offset: usize, length: u32): void;
36+
export declare function onBinary(offset: usize, length: u32): void;
37+
export declare function onTruncated(): void;
38+
}
39+
40+
var offset: usize = 0;
41+
42+
export function decode(length: usize): void {
43+
offset = 0;
44+
while (offset < length)
45+
decodeValue();
46+
if (offset != length)
47+
pson.onTruncated();
48+
}
49+
50+
function decodeValue(): void {
51+
var token: u32 = load<u8>(offset++);
52+
var size: u32;
53+
var long: u64;
54+
switch (token) {
55+
56+
case Token.NULL:
57+
pson.onNull();
58+
break;
59+
60+
case Token.TRUE:
61+
pson.onTrue();
62+
break;
63+
64+
case Token.FALSE:
65+
pson.onFalse();
66+
break;
67+
68+
case Token.EOBJECT:
69+
pson.onEObject();
70+
break;
71+
72+
case Token.EARRAY:
73+
pson.onEArray();
74+
break;
75+
76+
case Token.ESTRING:
77+
pson.onEString();
78+
break;
79+
80+
case Token.OBJECT:
81+
pson.onObject(size = readVarint32());
82+
while (size--) {
83+
decodeValue();
84+
decodeValue();
85+
}
86+
break;
87+
88+
case Token.ARRAY:
89+
pson.onArray(size = readVarint32());
90+
while (size--)
91+
decodeValue();
92+
break;
93+
94+
case Token.INTEGER:
95+
pson.onInteger(((size = readVarint32()) >> 1) ^ -(size & 1));
96+
break;
97+
98+
case Token.LONG:
99+
long = ((long = readVarint64()) >> 1) ^ -(long & 1);
100+
pson.onLong(<i32>long, <i32>(long >>> 32));
101+
break;
102+
103+
case Token.FLOAT:
104+
pson.onFloat(load<f32>(offset));
105+
offset += 4;
106+
break;
107+
108+
case Token.DOUBLE:
109+
pson.onDouble(load<f64>(offset));
110+
offset += 8;
111+
break;
112+
113+
case Token.STRING:
114+
size = readVarint32();
115+
pson.onString(offset, size);
116+
offset += size;
117+
break;
118+
119+
case Token.STRING_ADD:
120+
case Token.STRING_GET:
121+
// could be implemented via imports as well, but isn't necessary for this example
122+
throw new Error("not implemented");
123+
124+
case Token.BINARY:
125+
size = readVarint32();
126+
pson.onBinary(offset, size);
127+
offset += size;
128+
break;
129+
130+
default: // small integer?
131+
if (token > Token.MAX)
132+
throw new Error("unexpected token");
133+
pson.onInteger((token >> 1) ^ -(token & 1));
134+
break;
135+
}
136+
}
137+
138+
function readVarint32(): u32 {
139+
var value: u32 = 0;
140+
var shift: u32 = 0;
141+
do {
142+
var b = load<u8>(offset++);
143+
value |= <u32>(b & 0x7f) << (7 * shift++);
144+
} while (b & 0x80);
145+
return value;
146+
}
147+
148+
function readVarint64(): u64 {
149+
var value: u64 = 0;
150+
var shift: u64 = 0;
151+
do {
152+
var b = load<u8>(offset++);
153+
value |= <u64>(b & 0x7f) << (7 * shift++);
154+
} while (b & 0x80);
155+
return value;
156+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "../../../std/assembly.json",
3+
"include": [
4+
"./**/*.ts"
5+
]
6+
}

examples/pson/index.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
var fs = require("fs");
2+
3+
// Define imports. Just logs to console for the sake of this example.
4+
var pson = {
5+
onNull: function() {
6+
console.log("null");
7+
},
8+
onTrue: function() {
9+
console.log("true");
10+
},
11+
onFalse: function() {
12+
console.log("false");
13+
},
14+
onEObject: function() {
15+
console.log("{}");
16+
},
17+
onEArray: function() {
18+
console.log("[]");
19+
},
20+
onEString: function() {
21+
console.log("\"\"");
22+
},
23+
onObject: function(size) {
24+
console.log("{" + size + "}")
25+
},
26+
onArray: function(size) {
27+
console.log("[" + size + "]");
28+
},
29+
onInteger: function(value) {
30+
console.log("integer: " + value);
31+
},
32+
onLong: function(valueLow, valueHigh) {
33+
console.log("long: " + valueLow + ", " + valueHigh);
34+
},
35+
onFloat: function(value) {
36+
console.log("float: " + value);
37+
},
38+
onDouble: function(value) {
39+
console.log("double: " + value);
40+
},
41+
onString: function(offset, length) {
42+
console.log("string(length=" + length + "): " + new Buffer(mem.slice(offset, offset + length)).toString());
43+
},
44+
onBinary: function(offset, length) {
45+
console.log("binary(length=" + length + "): " + mem.slice(offset, offset + length));
46+
},
47+
onTruncated: function() {
48+
console.log("buffer is truncated :-(");
49+
}
50+
};
51+
52+
// Instantiate the module
53+
var mod = new WebAssembly.Module(fs.readFileSync(__dirname + "/pson.optimized.wasm"));
54+
var ins = new WebAssembly.Instance(mod, { pson: pson });
55+
var mem = new Uint8Array(ins.exports.memory.buffer);
56+
57+
// Export API
58+
exports.decode = function(buffer) {
59+
60+
// grow memory if necessary
61+
if (mem.length < buffer.length) {
62+
ins.exports.memory.grow(Math.ceil((buffer.length - mem.length) / 65536));
63+
mem = new Uint8Array(ins.exports.memory.buffer);
64+
}
65+
66+
// copy buffer to memory
67+
mem.set(buffer);
68+
69+
// start decoding (calls the imports defined above)
70+
ins.exports.decode(buffer.length);
71+
}

examples/pson/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "@assemblyscript/pson-example",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "npm run build:untouched && npm run build:optimized",
7+
"build:untouched": "asc assembly/pson.ts -b pson.untouched.wasm -t pson.untouched.wast --validate",
8+
"build:optimized": "asc -O assembly/pson.ts -b pson.optimized.wasm -t pson.optimized.wast --validate",
9+
"test": "node tests"
10+
},
11+
"devDependencies": {
12+
"pson": "^2.0.0"
13+
}
14+
}

examples/pson/tests/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
var Long = require("long");
2+
3+
var psonJS = require("pson");
4+
var psonWASM = require("..");
5+
6+
// encode in JS
7+
var buf = new psonJS.Encoder().encode({
8+
emptyObject: {},
9+
emptyArray: [],
10+
emptyString: "",
11+
object: {
12+
aSmallInt: 42,
13+
anInt: 9000,
14+
aLong: Long.MIN_VALUE.add(1)
15+
},
16+
array: [
17+
0.25, // fits into float
18+
0.1 // always a double
19+
],
20+
binary: Buffer.from([1, 2, 3])
21+
}).toBuffer();
22+
23+
// decode in WASM
24+
psonWASM.decode(buf);

0 commit comments

Comments
 (0)