diff --git a/README.md b/README.md
index 1a38ac83..989911d7 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,11 @@ Side effects:
- Good benchmark when comparing both versions
- 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
---------------
@@ -38,7 +43,7 @@ $> npm install
$> 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
diff --git a/assembly.d.ts b/assembly.d.ts
index a951c326..60c2df7e 100644
--- a/assembly.d.ts
+++ b/assembly.d.ts
@@ -87,17 +87,10 @@ declare function assert(isTrue: bool): void;
// internal decorators
-declare function global(name?: string): any;
-declare function struct(): any
+declare function global(): any;
declare function inline(): any;
-declare function allocates(): any;
-declare function operator(token: string, fn: any): any;
// standard library
-///
-///
-///
-///
-///
-///
+///
+///
diff --git a/src/compiler.ts b/src/compiler.ts
index b1e293ed..9ddf4b11 100644
--- a/src/compiler.ts
+++ b/src/compiler.ts
@@ -1624,59 +1624,54 @@ export class Compiler extends DiagnosticEmitter {
}
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
+ switch (expression.kind) {
- // null
- if (expression.kind == NodeKind.NULL) {
- if (contextualType.classType) // keep contextualType
- return this.options.target == Target.WASM64 ? this.module.createI64(0, 0) : this.module.createI32(0);
- if (this.options.target == Target.WASM64) {
- this.currentType = Type.u64;
- return this.module.createI64(0, 0);
- } else {
- this.currentType = Type.u32;
+ case NodeKind.NULL:
+ if (this.options.target == Target.WASM64) {
+ if (!contextualType.classType) {
+ assert(contextualType.kind == TypeKind.USIZE);
+ this.currentType = Type.usize64;
+ }
+ return this.module.createI64(0, 0);
+ }
+ if (!contextualType.classType) {
+ assert(contextualType.kind == TypeKind.USIZE);
+ this.currentType = Type.usize32;
+ }
return this.module.createI32(0);
- }
- // true
- } else if (expression.kind == NodeKind.TRUE) {
- this.currentType = Type.bool;
- return this.module.createI32(1);
+ case NodeKind.TRUE:
+ this.currentType = Type.bool;
+ return this.module.createI32(1);
- // false
- } else if (expression.kind == NodeKind.FALSE) {
- this.currentType = Type.bool;
- return this.module.createI32(0);
+ case NodeKind.FALSE:
+ this.currentType = Type.bool;
+ return this.module.createI32(0);
- // this
- } else if (expression.kind == NodeKind.THIS) {
- if (this.currentFunction.instanceMethodOf) {
- this.currentType = this.currentFunction.instanceMethodOf.type;
- 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.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
- return this.module.createUnreachable();
- }
+ case NodeKind.THIS:
+ if (this.currentFunction.instanceMethodOf) {
+ this.currentType = this.currentFunction.instanceMethodOf.type;
+ 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.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
+ return this.module.createUnreachable();
- if (expression.kind == NodeKind.IDENTIFIER) {
-
- // NaN
- if ((expression).name == "NaN")
- if (this.currentType.kind == TypeKind.F32)
- return this.module.createF32(NaN);
- else {
+ case NodeKind.IDENTIFIER:
+ // TODO: some sort of resolveIdentifier maybe
+ if ((expression).name == "NaN") {
+ if (this.currentType == Type.f32)
+ return this.module.createF32(NaN);
this.currentType = Type.f64;
return this.module.createF64(NaN);
}
-
- // Infinity
- if ((expression).name == "Infinity")
- if (this.currentType.kind == TypeKind.F32)
- return this.module.createF32(Infinity);
- else {
+ if ((expression).name == "Infinity") {
+ if (this.currentType == Type.f32)
+ return this.module.createF32(Infinity);
this.currentType = Type.f64;
return this.module.createF64(Infinity);
}
+ break;
}
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
diff --git a/src/glue/js.d.ts b/src/glue/js.d.ts
index 1a70fb15..7fb052f5 100644
--- a/src/glue/js.d.ts
+++ b/src/glue/js.d.ts
@@ -14,6 +14,7 @@ declare type bool = boolean;
// Raw memory access (here: Binaryen memory)
declare function store(ptr: usize, val: T): void;
declare function load(ptr: usize): T;
+declare function assert(isTrue: bool): void;
// Other things that might or might not be useful
declare function select(ifTrue: T, ifFalse: T, condition: bool): T;
diff --git a/std/array.d.ts b/std/array.d.ts
deleted file mode 100644
index 0bdc66c2..00000000
--- a/std/array.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-///
-
-declare class Array {
- length: i32;
- readonly capacity: i32;
- readonly data: usize;
- constructor(capacity: i32);
-}
-
-declare class Int8Array extends Array {}
-declare class Int16Array extends Array {}
-declare class Int32Array extends Array {}
-declare class Uint8Array extends Array {}
-declare class Uint16Array extends Array {}
-declare class Uint32Array extends Array {}
-declare class Float32Array extends Array {}
-declare class Float64Array extends Array {}
diff --git a/std/carray.d.ts b/std/carray.d.ts
new file mode 100644
index 00000000..145da600
--- /dev/null
+++ b/std/carray.d.ts
@@ -0,0 +1,6 @@
+///
+
+declare class CArray {
+ [key: number]: T;
+ constructor(capacity: usize);
+}
diff --git a/std/cstring.d.ts b/std/cstring.d.ts
new file mode 100644
index 00000000..a0fed1ab
--- /dev/null
+++ b/std/cstring.d.ts
@@ -0,0 +1,5 @@
+///
+
+declare class CString extends CArray {
+ constructor(text: string);
+}
diff --git a/std/error.d.ts b/std/error.d.ts
deleted file mode 100644
index 20055be8..00000000
--- a/std/error.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-///
-
-declare class Error {
- message: string;
- constructor(message: string);
-}
-
-declare class RangeError extends Error {}
-declare class ReferenceError extends Error {}
-declare class TypeError extends Error {}
diff --git a/std/impl/array.ts b/std/impl/array.ts
deleted file mode 100644
index f8afbe23..00000000
--- a/std/impl/array.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-///
-
-@global()
-class Array {
-
- 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() * capacity);
- }
-}
diff --git a/std/impl/carray.ts b/std/impl/carray.ts
new file mode 100644
index 00000000..5a3b9d96
--- /dev/null
+++ b/std/impl/carray.ts
@@ -0,0 +1,29 @@
+///
+
+/** A C-compatible Array class. */
+@global()
+class CArray {
+
+ /** Constructs a new C-Array of the specified capacity. */
+ constructor(capacity: usize) {
+ return unsafe_cast(Memory.allocate(capacity * sizeof()));
+ }
+
+ /** Gets the element at the specified index using bracket notation. */
+ @inline()
+ "[]"(index: usize): T {
+ return load(unsafe_cast(this) + index * sizeof());
+ }
+
+ /** Sets the element at the specified index using bracket notation. */
+ @inline()
+ "[]="(index: usize, value: T): T {
+ store(unsafe_cast(this) + index * sizeof(), value);
+ return value;
+ }
+
+ /** Disposes this instance and the memory associated with it. */
+ dispose(): void {
+ Memory.dispose(unsafe_cast(this));
+ }
+}
diff --git a/std/impl/cstring.ts b/std/impl/cstring.ts
new file mode 100644
index 00000000..b8d7675a
--- /dev/null
+++ b/std/impl/cstring.ts
@@ -0,0 +1,47 @@
+///
+
+/** A C-compatible string class. */
+@global()
+class CString extends CArray {
+
+ /** Constructs a new C-String from a String. */
+ constructor(text: string) {
+ super(text.length * 2 + 1);
+ let idx: usize = unsafe_cast(this);
+ for (let i: usize = 0, k: usize = (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(idx++, u as u8);
+ else if (u <= 0x7FF) {
+ // TODO: maybe combine multiple stores into the next larger one
+ store(idx++, (0xC0 | (u >>> 6) ) as u8);
+ store(idx++, (0x80 | ( u & 63)) as u8);
+ } else if (u <= 0xFFFF) {
+ store(idx++, (0xE0 | (u >>> 12) ) as u8);
+ store(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
+ store(idx++, (0x80 | ( u & 63)) as u8);
+ } else if (u <= 0x1FFFFF) {
+ store(idx++, (0xF0 | (u >>> 18) ) as u8);
+ store(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
+ store(idx++, (0x80 | ( u & 63)) as u8);
+ } else if (u <= 0x3FFFFFF) {
+ store(idx++, (0xF8 | (u >>> 24) ) as u8);
+ store(idx++, (0x80 | ((u >>> 18) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
+ store(idx++, (0x80 | ( u & 63)) as u8);
+ } else {
+ store(idx++, (0xFC | (u >>> 30) ) as u8);
+ store(idx++, (0x80 | ((u >>> 24) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 18) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
+ store(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
+ store(idx++, (0x80 | ( u & 63)) as u8);
+ }
+ }
+ store(idx, 0);
+ }
+}
diff --git a/std/impl/error.ts b/std/impl/error.ts
deleted file mode 100644
index ac40b47d..00000000
--- a/std/impl/error.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-///
-
-@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 {}
diff --git a/std/impl/map.ts b/std/impl/map.ts
deleted file mode 100644
index 41081f01..00000000
--- a/std/impl/map.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-///
-
-@global()
-class Map {
- 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 {
- }
-}
diff --git a/std/impl/math.ts b/std/impl/math.ts
deleted file mode 100644
index 70631e72..00000000
--- a/std/impl/math.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-///
-
-@global()
-class Math {
-}
diff --git a/std/impl/memory.ts b/std/impl/memory.ts
index 5309cf5a..7ad2e8d7 100644
--- a/std/impl/memory.ts
+++ b/std/impl/memory.ts
@@ -1,27 +1,21 @@
///
+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()
class Memory {
static allocate(size: usize): usize {
- const ptr: usize = load(sizeof());
- store(sizeof(), ptr + size);
+ const ptr: usize = HEAP_OFFSET;
+ HEAP_OFFSET += size;
+ if ((HEAP_OFFSET & MEMORY_ALIGN_MASK) != 0)
+ HEAP_OFFSET = (HEAP_OFFSET | MEMORY_ALIGN_MASK) + 1;
return ptr;
}
- static free(ptr: usize): void {
- }
-
- static copy(src: usize, dst: usize, count: usize): void {
- for (let i: usize = 0; i < count; ++i)
- store(dst + i, load(src + i));
- }
-
- static compare(src: usize, dst: usize, count: usize): i32 {
- for (let i: usize = 0; i < count; ++i) {
- const d: i32 = (load(src + i) as i32) - (load(dst + i) as i32);
- if (d) return d;
- }
- return 0;
+ static dispose(ptr: usize): void {
+ // just a big chunk of non-disposable memory for now
}
}
diff --git a/std/impl/set.ts b/std/impl/set.ts
deleted file mode 100644
index 0da35c34..00000000
--- a/std/impl/set.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-///
-
-@global()
-class Set {
-}
diff --git a/std/impl/string.ts b/std/impl/string.ts
deleted file mode 100644
index 10643885..00000000
--- a/std/impl/string.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-///
-
-@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(data, length);
- return classof(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(data, combinedLength);
- Memory.copy(pointerof(a) + 4, data + 4, aByteLength);
- Memory.copy(pointerof(b) + 4, data + 4 + aByteLength, bByteLength);
- return classof(data);
- }
-
- charCodeAt(index: i32): u16 {
- if (index < 0 || index > this.length)
- throw new RangeError("index out of bounds");
- return load(pointerof(this) + 4 + index << 1);
- }
-
- concat(other: String): String {
- return String.concat(this, other);
- }
-}
diff --git a/std/impl/tsconfig.json b/std/impl/tsconfig.json
index 0809326f..6241f0cf 100644
--- a/std/impl/tsconfig.json
+++ b/std/impl/tsconfig.json
@@ -4,12 +4,8 @@
"experimentalDecorators": true
},
"files": [
- "array.ts",
- "error.ts",
- "map.ts",
- "math.ts",
- "memory.ts",
- "set.ts",
- "string.ts"
+ "carray.ts",
+ "cstring.ts",
+ "memory.ts"
]
}
\ No newline at end of file
diff --git a/std/map.d.ts b/std/map.d.ts
deleted file mode 100644
index 790b8184..00000000
--- a/std/map.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/std/math.d.ts b/std/math.d.ts
deleted file mode 100644
index 78794f4f..00000000
--- a/std/math.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-///
-
-declare class Math {
-}
diff --git a/std/memory.d.ts b/std/memory.d.ts
index 9354cec6..cdd44d71 100644
--- a/std/memory.d.ts
+++ b/std/memory.d.ts
@@ -2,7 +2,5 @@
declare class Memory {
static allocate(size: usize): usize;
- static free(ptr: usize): void;
- static copy(src: usize, dst: usize, count: usize): void;
- static compare(src: usize, dst: usize, count: usize): i32;
+ static dispose(ptr: usize): void;
}
diff --git a/std/set.d.ts b/std/set.d.ts
deleted file mode 100644
index 428f9efe..00000000
--- a/std/set.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-///
-
-declare class Set {
-}
diff --git a/std/string.d.ts b/std/string.d.ts
deleted file mode 100644
index d3b07f84..00000000
--- a/std/string.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-///
-
-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;
-}
diff --git a/std/tsconfig.json b/std/tsconfig.json
index 2516bc29..6963be52 100644
--- a/std/tsconfig.json
+++ b/std/tsconfig.json
@@ -4,12 +4,8 @@
"experimentalDecorators": true
},
"files": [
- "array.d.ts",
- "error.d.ts",
- "map.d.ts",
- "math.d.ts",
- "memory.d.ts",
- "set.d.ts",
- "string.d.ts"
+ "carray.d.ts",
+ "cstring.d.ts",
+ "memory.d.ts"
]
}
\ No newline at end of file
diff --git a/tests/compiler/game-of-life.html b/tests/compiler/game-of-life.html
index 31f791bc..12ff57b0 100644
--- a/tests/compiler/game-of-life.html
+++ b/tests/compiler/game-of-life.html
@@ -1,36 +1,61 @@
-
-