mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Some thoughts on an initial stdlib to get things going
This commit is contained in:
parent
325ecf5165
commit
59dafc8d22
@ -26,6 +26,11 @@ Side effects:
|
|||||||
- Good benchmark when comparing both versions
|
- Good benchmark when comparing both versions
|
||||||
- Benefits standard library design ideas
|
- Benefits standard library design ideas
|
||||||
|
|
||||||
|
How does it work?
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
AssemblyScript NEXT compiles a subset (or variant) of TypeScript to Binaryen IR. The resulting module can then be optimized, emitted in text or binary format, or even be converted to asm.js as a polyfill.
|
||||||
|
|
||||||
Getting started
|
Getting started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -38,7 +43,7 @@ $> npm install
|
|||||||
$> node bin\asc yourModule.ts
|
$> node bin\asc yourModule.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
Building an UMD bundle to `dist/assemblyscript.js` (does not bundle [binaryen.js](https://github.com/AssemblyScript/binaryen.js):
|
Building an UMD bundle to `dist/assemblyscript.js` (does not bundle [binaryen.js](https://github.com/AssemblyScript/binaryen.js)):
|
||||||
|
|
||||||
```
|
```
|
||||||
$> npm run build
|
$> npm run build
|
||||||
|
13
assembly.d.ts
vendored
13
assembly.d.ts
vendored
@ -87,17 +87,10 @@ declare function assert(isTrue: bool): void;
|
|||||||
|
|
||||||
// internal decorators
|
// internal decorators
|
||||||
|
|
||||||
declare function global(name?: string): any;
|
declare function global(): any;
|
||||||
declare function struct(): any
|
|
||||||
declare function inline(): any;
|
declare function inline(): any;
|
||||||
declare function allocates(): any;
|
|
||||||
declare function operator(token: string, fn: any): any;
|
|
||||||
|
|
||||||
// standard library
|
// standard library
|
||||||
|
|
||||||
/// <reference path="./std/array.d.ts" />
|
/// <reference path="./std/carray.d.ts" />
|
||||||
/// <reference path="./std/map.d.ts" />
|
/// <reference path="./std/cstring.d.ts" />
|
||||||
/// <reference path="./std/math.d.ts" />
|
|
||||||
/// <reference path="./std/memory.d.ts" />
|
|
||||||
/// <reference path="./std/set.d.ts" />
|
|
||||||
/// <reference path="./std/string.d.ts" />
|
|
||||||
|
@ -1624,59 +1624,54 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
|
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
|
||||||
|
switch (expression.kind) {
|
||||||
|
|
||||||
// null
|
case NodeKind.NULL:
|
||||||
if (expression.kind == NodeKind.NULL) {
|
if (this.options.target == Target.WASM64) {
|
||||||
if (contextualType.classType) // keep contextualType
|
if (!contextualType.classType) {
|
||||||
return this.options.target == Target.WASM64 ? this.module.createI64(0, 0) : this.module.createI32(0);
|
assert(contextualType.kind == TypeKind.USIZE);
|
||||||
if (this.options.target == Target.WASM64) {
|
this.currentType = Type.usize64;
|
||||||
this.currentType = Type.u64;
|
}
|
||||||
return this.module.createI64(0, 0);
|
return this.module.createI64(0, 0);
|
||||||
} else {
|
}
|
||||||
this.currentType = Type.u32;
|
if (!contextualType.classType) {
|
||||||
|
assert(contextualType.kind == TypeKind.USIZE);
|
||||||
|
this.currentType = Type.usize32;
|
||||||
|
}
|
||||||
return this.module.createI32(0);
|
return this.module.createI32(0);
|
||||||
}
|
|
||||||
|
|
||||||
// true
|
case NodeKind.TRUE:
|
||||||
} else if (expression.kind == NodeKind.TRUE) {
|
this.currentType = Type.bool;
|
||||||
this.currentType = Type.bool;
|
return this.module.createI32(1);
|
||||||
return this.module.createI32(1);
|
|
||||||
|
|
||||||
// false
|
case NodeKind.FALSE:
|
||||||
} else if (expression.kind == NodeKind.FALSE) {
|
this.currentType = Type.bool;
|
||||||
this.currentType = Type.bool;
|
return this.module.createI32(0);
|
||||||
return this.module.createI32(0);
|
|
||||||
|
|
||||||
// this
|
case NodeKind.THIS:
|
||||||
} else if (expression.kind == NodeKind.THIS) {
|
if (this.currentFunction.instanceMethodOf) {
|
||||||
if (this.currentFunction.instanceMethodOf) {
|
this.currentType = this.currentFunction.instanceMethodOf.type;
|
||||||
this.currentType = this.currentFunction.instanceMethodOf.type;
|
return this.module.createGetLocal(0, this.options.target == Target.WASM64 ? NativeType.I64 : NativeType.I32);
|
||||||
return this.module.createGetLocal(0, this.options.target == Target.WASM64 ? NativeType.I64 : NativeType.I32);
|
}
|
||||||
}
|
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
|
||||||
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
|
this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
|
||||||
this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
|
return this.module.createUnreachable();
|
||||||
return this.module.createUnreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expression.kind == NodeKind.IDENTIFIER) {
|
case NodeKind.IDENTIFIER:
|
||||||
|
// TODO: some sort of resolveIdentifier maybe
|
||||||
// NaN
|
if ((<IdentifierExpression>expression).name == "NaN") {
|
||||||
if ((<IdentifierExpression>expression).name == "NaN")
|
if (this.currentType == Type.f32)
|
||||||
if (this.currentType.kind == TypeKind.F32)
|
return this.module.createF32(NaN);
|
||||||
return this.module.createF32(NaN);
|
|
||||||
else {
|
|
||||||
this.currentType = Type.f64;
|
this.currentType = Type.f64;
|
||||||
return this.module.createF64(NaN);
|
return this.module.createF64(NaN);
|
||||||
}
|
}
|
||||||
|
if ((<IdentifierExpression>expression).name == "Infinity") {
|
||||||
// Infinity
|
if (this.currentType == Type.f32)
|
||||||
if ((<IdentifierExpression>expression).name == "Infinity")
|
return this.module.createF32(Infinity);
|
||||||
if (this.currentType.kind == TypeKind.F32)
|
|
||||||
return this.module.createF32(Infinity);
|
|
||||||
else {
|
|
||||||
this.currentType = Type.f64;
|
this.currentType = Type.f64;
|
||||||
return this.module.createF64(Infinity);
|
return this.module.createF64(Infinity);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
|
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
|
||||||
|
1
src/glue/js.d.ts
vendored
1
src/glue/js.d.ts
vendored
@ -14,6 +14,7 @@ declare type bool = boolean;
|
|||||||
// Raw memory access (here: Binaryen memory)
|
// Raw memory access (here: Binaryen memory)
|
||||||
declare function store<T = u8>(ptr: usize, val: T): void;
|
declare function store<T = u8>(ptr: usize, val: T): void;
|
||||||
declare function load<T = u8>(ptr: usize): T;
|
declare function load<T = u8>(ptr: usize): T;
|
||||||
|
declare function assert(isTrue: bool): void;
|
||||||
|
|
||||||
// Other things that might or might not be useful
|
// Other things that might or might not be useful
|
||||||
declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;
|
declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;
|
||||||
|
17
std/array.d.ts
vendored
17
std/array.d.ts
vendored
@ -1,17 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
||||||
|
|
||||||
declare class Array<T> {
|
|
||||||
length: i32;
|
|
||||||
readonly capacity: i32;
|
|
||||||
readonly data: usize;
|
|
||||||
constructor(capacity: i32);
|
|
||||||
}
|
|
||||||
|
|
||||||
declare class Int8Array extends Array<i8> {}
|
|
||||||
declare class Int16Array extends Array<i16> {}
|
|
||||||
declare class Int32Array extends Array<i32> {}
|
|
||||||
declare class Uint8Array extends Array<u8> {}
|
|
||||||
declare class Uint16Array extends Array<u16> {}
|
|
||||||
declare class Uint32Array extends Array<u32> {}
|
|
||||||
declare class Float32Array extends Array<f32> {}
|
|
||||||
declare class Float64Array extends Array<f64> {}
|
|
6
std/carray.d.ts
vendored
Normal file
6
std/carray.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class CArray<T> {
|
||||||
|
[key: number]: T;
|
||||||
|
constructor(capacity: usize);
|
||||||
|
}
|
5
std/cstring.d.ts
vendored
Normal file
5
std/cstring.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class CString extends CArray<u8> {
|
||||||
|
constructor(text: string);
|
||||||
|
}
|
10
std/error.d.ts
vendored
10
std/error.d.ts
vendored
@ -1,10 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
||||||
|
|
||||||
declare class Error {
|
|
||||||
message: string;
|
|
||||||
constructor(message: string);
|
|
||||||
}
|
|
||||||
|
|
||||||
declare class RangeError extends Error {}
|
|
||||||
declare class ReferenceError extends Error {}
|
|
||||||
declare class TypeError extends Error {}
|
|
@ -1,17 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class Array<T> {
|
|
||||||
|
|
||||||
length: i32;
|
|
||||||
readonly capacity: i32;
|
|
||||||
readonly data: usize;
|
|
||||||
|
|
||||||
constructor(capacity: i32) {
|
|
||||||
if (capacity < 0)
|
|
||||||
throw new RangeError("capacity out of bounds");
|
|
||||||
this.length = capacity;
|
|
||||||
this.capacity = capacity;
|
|
||||||
this.data = Memory.allocate(sizeof<T>() * capacity);
|
|
||||||
}
|
|
||||||
}
|
|
29
std/impl/carray.ts
Normal file
29
std/impl/carray.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/// <reference path="../../assembly.d.ts" />
|
||||||
|
|
||||||
|
/** A C-compatible Array class. */
|
||||||
|
@global()
|
||||||
|
class CArray<T> {
|
||||||
|
|
||||||
|
/** Constructs a new C-Array of the specified capacity. */
|
||||||
|
constructor(capacity: usize) {
|
||||||
|
return unsafe_cast<usize,this>(Memory.allocate(capacity * sizeof<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the element at the specified index using bracket notation. */
|
||||||
|
@inline()
|
||||||
|
"[]"(index: usize): T {
|
||||||
|
return load<T>(unsafe_cast<this,usize>(this) + index * sizeof<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the element at the specified index using bracket notation. */
|
||||||
|
@inline()
|
||||||
|
"[]="(index: usize, value: T): T {
|
||||||
|
store<T>(unsafe_cast<this,usize>(this) + index * sizeof<T>(), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disposes this instance and the memory associated with it. */
|
||||||
|
dispose(): void {
|
||||||
|
Memory.dispose(unsafe_cast<this,usize>(this));
|
||||||
|
}
|
||||||
|
}
|
47
std/impl/cstring.ts
Normal file
47
std/impl/cstring.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/// <reference path="../../assembly.d.ts" />
|
||||||
|
|
||||||
|
/** A C-compatible string class. */
|
||||||
|
@global()
|
||||||
|
class CString extends CArray<u8> {
|
||||||
|
|
||||||
|
/** Constructs a new C-String from a String. */
|
||||||
|
constructor(text: string) {
|
||||||
|
super(text.length * 2 + 1);
|
||||||
|
let idx: usize = unsafe_cast<this,usize>(this);
|
||||||
|
for (let i: usize = 0, k: usize = (<string>str).length; i < k; ++i) {
|
||||||
|
let u: i32 = text.charCodeAt(i);
|
||||||
|
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
|
||||||
|
u = 0x10000 + ((u & 0x3FF) << 10) | (text.charCodeAt(++i) & 0x3FF);
|
||||||
|
if (u <= 0x7F)
|
||||||
|
store<u8>(idx++, u as u8);
|
||||||
|
else if (u <= 0x7FF) {
|
||||||
|
// TODO: maybe combine multiple stores into the next larger one
|
||||||
|
store<u8>(idx++, (0xC0 | (u >>> 6) ) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||||
|
} else if (u <= 0xFFFF) {
|
||||||
|
store<u8>(idx++, (0xE0 | (u >>> 12) ) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||||
|
} else if (u <= 0x1FFFFF) {
|
||||||
|
store<u8>(idx++, (0xF0 | (u >>> 18) ) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||||
|
} else if (u <= 0x3FFFFFF) {
|
||||||
|
store<u8>(idx++, (0xF8 | (u >>> 24) ) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 18) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||||
|
} else {
|
||||||
|
store<u8>(idx++, (0xFC | (u >>> 30) ) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 24) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 18) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
|
||||||
|
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
store<u8>(idx, 0);
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class Error {
|
|
||||||
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
constructor(message: string) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class RangeError extends Error {}
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class ReferenceError extends Error {}
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class TypeError extends Error {}
|
|
@ -1,22 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class Map<K,V> {
|
|
||||||
private keys: K[];
|
|
||||||
private values: V[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.keys = [];
|
|
||||||
this.values = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
has(key: K): bool {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key: K, value: V): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class Math {
|
|
||||||
}
|
|
@ -1,27 +1,21 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
/// <reference path="../../assembly.d.ts" />
|
||||||
|
|
||||||
|
const MEMORY_ALIGN_LOG2: usize = 3;
|
||||||
|
const MEMORY_ALIGN_SIZE: usize = 1 << MEMORY_ALIGN_LOG2;
|
||||||
|
const MEMORY_ALIGN_MASK: usize = MEMORY_ALIGN_SIZE - 1;
|
||||||
|
|
||||||
@global()
|
@global()
|
||||||
class Memory {
|
class Memory {
|
||||||
|
|
||||||
static allocate(size: usize): usize {
|
static allocate(size: usize): usize {
|
||||||
const ptr: usize = load<usize>(sizeof<usize>());
|
const ptr: usize = HEAP_OFFSET;
|
||||||
store<usize>(sizeof<usize>(), ptr + size);
|
HEAP_OFFSET += size;
|
||||||
|
if ((HEAP_OFFSET & MEMORY_ALIGN_MASK) != 0)
|
||||||
|
HEAP_OFFSET = (HEAP_OFFSET | MEMORY_ALIGN_MASK) + 1;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static free(ptr: usize): void {
|
static dispose(ptr: usize): void {
|
||||||
}
|
// just a big chunk of non-disposable memory for now
|
||||||
|
|
||||||
static copy(src: usize, dst: usize, count: usize): void {
|
|
||||||
for (let i: usize = 0; i < count; ++i)
|
|
||||||
store<u8>(dst + i, load<u8>(src + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
static compare(src: usize, dst: usize, count: usize): i32 {
|
|
||||||
for (let i: usize = 0; i < count; ++i) {
|
|
||||||
const d: i32 = (load<u8>(src + i) as i32) - (load<u8>(dst + i) as i32);
|
|
||||||
if (d) return d;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
class Set<T> {
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/// <reference path="../../assembly.d.ts" />
|
|
||||||
|
|
||||||
@global()
|
|
||||||
@allocates()
|
|
||||||
@operator("==", String.equals)
|
|
||||||
@operator("!=", String.notEquals)
|
|
||||||
@operator("+", String.concat)
|
|
||||||
class String {
|
|
||||||
|
|
||||||
readonly length: i32;
|
|
||||||
|
|
||||||
constructor(length: i32) {
|
|
||||||
if (length < 0)
|
|
||||||
throw new RangeError("invalid length");
|
|
||||||
const data: usize = Memory.allocate(4 + length);
|
|
||||||
store<i32>(data, length);
|
|
||||||
return classof<String>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromCharCode(c1: i32 /* sic */, c2: i32 = -1): String {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
static equals(a: String, b: String): bool {
|
|
||||||
const aLength: i32 = a.length;
|
|
||||||
return aLength == b.length && !Memory.compare(pointerof(a) + 4, pointerof(b) + 4, aLength << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static notEquals(a: String, b: String): bool {
|
|
||||||
const aLength: i32 = a.length;
|
|
||||||
return aLength != b.length || Memory.compare(pointerof(a) + 4, pointerof(b) + 4, aLength << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static concat(a: String, b: String): String {
|
|
||||||
const aLength: i32 = a.length;
|
|
||||||
const bLength: i32 = b.length;
|
|
||||||
const combinedLength: i32 = aLength + bLength;
|
|
||||||
if (combinedLength < 0)
|
|
||||||
throw new RangeError("invalid length");
|
|
||||||
const aByteLength: i32 = aLength << 1;
|
|
||||||
const bByteLength: i32 = bLength << 1;
|
|
||||||
const data: usize = Memory.allocate(4 + combinedLength);
|
|
||||||
store<i32>(data, combinedLength);
|
|
||||||
Memory.copy(pointerof(a) + 4, data + 4, aByteLength);
|
|
||||||
Memory.copy(pointerof(b) + 4, data + 4 + aByteLength, bByteLength);
|
|
||||||
return classof<String>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
charCodeAt(index: i32): u16 {
|
|
||||||
if (index < 0 || index > this.length)
|
|
||||||
throw new RangeError("index out of bounds");
|
|
||||||
return load<u32>(pointerof(this) + 4 + index << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
concat(other: String): String {
|
|
||||||
return String.concat(this, other);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,12 +4,8 @@
|
|||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"array.ts",
|
"carray.ts",
|
||||||
"error.ts",
|
"cstring.ts",
|
||||||
"map.ts",
|
"memory.ts"
|
||||||
"math.ts",
|
|
||||||
"memory.ts",
|
|
||||||
"set.ts",
|
|
||||||
"string.ts"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
1
std/map.d.ts
vendored
1
std/map.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
4
std/math.d.ts
vendored
4
std/math.d.ts
vendored
@ -1,4 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
||||||
|
|
||||||
declare class Math {
|
|
||||||
}
|
|
4
std/memory.d.ts
vendored
4
std/memory.d.ts
vendored
@ -2,7 +2,5 @@
|
|||||||
|
|
||||||
declare class Memory {
|
declare class Memory {
|
||||||
static allocate(size: usize): usize;
|
static allocate(size: usize): usize;
|
||||||
static free(ptr: usize): void;
|
static dispose(ptr: usize): void;
|
||||||
static copy(src: usize, dst: usize, count: usize): void;
|
|
||||||
static compare(src: usize, dst: usize, count: usize): i32;
|
|
||||||
}
|
}
|
||||||
|
4
std/set.d.ts
vendored
4
std/set.d.ts
vendored
@ -1,4 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
||||||
|
|
||||||
declare class Set<T> {
|
|
||||||
}
|
|
11
std/string.d.ts
vendored
11
std/string.d.ts
vendored
@ -1,11 +0,0 @@
|
|||||||
/// <reference path="../assembly.d.ts" />
|
|
||||||
|
|
||||||
declare class String {
|
|
||||||
readonly length: i32;
|
|
||||||
constructor(length: i32);
|
|
||||||
static fromCharCode(c1: i32, c2?: i32);
|
|
||||||
static equals(a: string, b: string): bool;
|
|
||||||
static concat(a: string, b: string): string;
|
|
||||||
charCodeAt(index: i32): u16;
|
|
||||||
concat(other: string): string;
|
|
||||||
}
|
|
@ -4,12 +4,8 @@
|
|||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"array.d.ts",
|
"carray.d.ts",
|
||||||
"error.d.ts",
|
"cstring.d.ts",
|
||||||
"map.d.ts",
|
"memory.d.ts"
|
||||||
"math.d.ts",
|
|
||||||
"memory.d.ts",
|
|
||||||
"set.d.ts",
|
|
||||||
"string.d.ts"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,36 +1,61 @@
|
|||||||
<canvas id="canvas" width="640" height="480"></canvas>
|
<canvas id="canvas" width="640" height="480"></canvas>
|
||||||
<script src="../../node_modules/binaryen/index.js"></script>
|
<script src="../../node_modules/binaryen/index.js"></script><script>
|
||||||
<script>
|
|
||||||
fetch("game-of-life.optimized.wast").then(response =>
|
// Fetch the .wast (just because we dont's store the .wasm in git)
|
||||||
response.text()
|
fetch("game-of-life.optimized.wast").then(response => response.text()).then(text => {
|
||||||
).then(text => {
|
|
||||||
let buffer = Binaryen.parseText(text).emitBinary();
|
// Convert it to binary format
|
||||||
|
var buffer = Binaryen.parseText(text).emitBinary();
|
||||||
|
|
||||||
|
// Instantiate the module
|
||||||
return WebAssembly.instantiate(buffer, {});
|
return WebAssembly.instantiate(buffer, {});
|
||||||
|
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
let cnv = document.getElementById("canvas");
|
var module = result.instance;
|
||||||
let ctx = cnv.getContext("2d");
|
|
||||||
let w = cnv.width, h = cnv.height, s = w * h, S = s + s;
|
// Set up the canvas with a 2D rendering context
|
||||||
if (result.instance.exports.memory.buffer.byteLength < S)
|
var cnv = document.getElementById("canvas");
|
||||||
result.instance.exports.memory.grow(Math.ceil(S / 65536) - 1);
|
var ctx = cnv.getContext("2d");
|
||||||
let mem = new Uint8Array(result.instance.exports.memory.buffer);
|
var w = cnv.width,
|
||||||
for (let y = 0; y < h; ++y)
|
h = cnv.height,
|
||||||
for (let x = 0; x < w; ++x)
|
s = w * h, // memory required to store either input or output
|
||||||
|
S = s + s; // total memory required to store input and output
|
||||||
|
|
||||||
|
// Grow the (exported) memory if it's size isn't sufficient
|
||||||
|
var memory = module.exports.memory;
|
||||||
|
if (memory.buffer.byteLength < S)
|
||||||
|
memory.grow(Math.ceil((S - memory.buffer.byteLength) / 65536));
|
||||||
|
|
||||||
|
// Fill input at [0, s-1] with random cells
|
||||||
|
var mem = new Uint8Array(memory.buffer);
|
||||||
|
for (var y = 0; y < h; ++y)
|
||||||
|
for (var x = 0; x < w; ++x)
|
||||||
mem[y * w + x] = Math.random() > 0.1 ? 0 : 1;
|
mem[y * w + x] = Math.random() > 0.1 ? 0 : 1;
|
||||||
result.instance.exports.init(w, h);
|
|
||||||
setInterval(function() {
|
// Initialize with width and height
|
||||||
result.instance.exports.step();
|
module.exports.init(w, h);
|
||||||
mem.set(mem.subarray(s, S), 0);
|
|
||||||
}, 33);
|
// Update about 30 times a second
|
||||||
|
function update() {
|
||||||
|
setTimeout(update, 33);
|
||||||
|
module.exports.step();
|
||||||
|
mem.set(mem.subarray(s, S), 0); // copy output -> input
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep rendering the output at [s, 2*s-1]
|
||||||
function render() {
|
function render() {
|
||||||
requestAnimationFrame(render);
|
requestAnimationFrame(render);
|
||||||
ctx.clearRect(0, 0, w, h);
|
ctx.clearRect(0, 0, w, h);
|
||||||
ctx.fillStyle = "#333";
|
ctx.fillStyle = "#333";
|
||||||
for (let y = 0; y < h; ++y)
|
for (var y = 0; y < h; ++y)
|
||||||
for (let x = 0; x < w; ++x)
|
for (var x = 0; x < w; ++x)
|
||||||
if (mem[s + y * w + x])
|
if (mem[s + y * w + x])
|
||||||
ctx.fillRect(x, y, 1, 1);
|
ctx.fillRect(x, y, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
render();
|
render();
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user