Peculiarities

Special features that exist for the sole reason of why not.

Annotations

Decorators work more like actual compiler annotations in AssemblyScript.

Annotation

Description

@inline

Requests inlining of a constant or function.

@lazy

Requests lazy compilation of a variable. Useful to avoid unnecessary globals.

@global

Registers an element to be part of the global scope.

@external

Changes the external name of an imported element. @external(module, name) changes both the module and element name, @external(name) changes the element name only.

@operator,

@operator.binary

Annotates a method as a binary operator overload. See below.

@operator.prefix

Annotates a method as a unary prefix operator overload. See below.

@operator.postfix

Annotates a method as a unary postfix operator overload. See below.

Custom decorators can be given meaning by using a transform.

Operator overloads

Operator overloads can only be used on class methods. The respective argument types must match the class type.

Binary operations

@operator(OP)
static __op(left: T, right :T): T { ... }
@operator(OP)
__op(right: T): T { ... }

OP

Description

"[]"

Checked indexed get

"[]="

Checked indexed set

"{}"

Unchecked indexed get

"{}="

Unchecked indexed set

"=="

Equality

"!="

Inequality

">"

Greater than

">="

Greater than or equal

"<"

Less than

"<="

Less than or equal

">>"

Arithmetic right shift

">>>"

Logical right shift

"<<"

Left shift

"&"

Bitwise AND

"|"

Bitwise OR

"^"

Bitwise XOR

"+"

Addition

"-"

Subtraction

"*"

Multiplication

"/"

Division

"**"

Exponentiation

"%"

Remainder

The === operation cannot be overloaded (is identity equality).

Unary prefix operations

@operator.prefix(OP)
static __op(self: T): T { ... }
@operator.prefix(OP)
__op(): T { ... }

OP

Description

Notes

"!"

Logical NOT

"~"

Bitwise NOT

"+"

Unary plus

"-"

Unary negation

"++"

Prefix increment

Instance overload reassigns

"--"

Prefix decrement

Instance overload reassigns

Note that increment and decrement overloads can have slightly different semantics. If the overload is declared as an instance method, on ++a the compiler does emit code that reassigns the resulting value to a while if the overload is declared static, the overload behaves like any other overload, skipping the otherwise implicit assignment.

Unary postfix operations

@operator.postfix(OP)
static __op(self: T): T { ... }
@operator.postfix(OP)
__op(): T { ... }

OP

Description

Notes

"++"

Postfix increment

Instance overload reassigns

"--"

Postfix decrement

Instance overload reassigns

Overloaded postfix operations do not preserve the original value automatically.

Range limits

The following range limits are present as global constants for convenience:

Constant

Value

i8.MIN_VALUE: i8

-128

i8.MAX_VALUE: i8

127

i16.MIN_VALUE: i16

-32768

i16.MAX_VALUE: i16

32767

i32.MIN_VALUE: i32

-2147483648

i32.MAX_VALUE: i32

2147483647

i64.MIN_VALUE: i64

-9223372036854775808

i64.MAX_VALUE: i64

9223372036854775807

isize.MIN_VALUE: isize

target specific: either i32.MIN_VALUE or i64.MIN_VALUE

isize.MAX_VALUE: isize

target specific: either i32.MAX_VALUE or i64.MAX_VALUE

u8.MIN_VALUE: u8

0

u8.MAX_VALUE: u8

255

u16.MIN_VALUE: u16

0

u16.MAX_VALUE: u16

65535

u32.MIN_VALUE: u32

0

u32.MAX_VALUE: u32

4294967295

u64.MIN_VALUE: u64

0

u64.MAX_VALUE: u64

18446744073709551615

usize.MIN_VALUE: usize

0

usize.MAX_VALUE: usize

target specific: either u32.MAX_VALUE or u64.MAX_VALUE

bool.MIN_VALUE: bool

0

bool.MAX_VALUE: bool

1

f32.MIN_VALUE: f32

-3.40282347e+38

f32.MAX_VALUE: f32

3.40282347e+38

f32.MIN_SAFE_INTEGER: f32

-16777215

f32.MAX_SAFE_INTEGER: f32

16777215

f32.EPSILON: f32

1.19209290e-07

f64.MIN_VALUE: f64

-1.7976931348623157e+308

f64.MAX_VALUE: f64

1.7976931348623157e+308

f64.MIN_SAFE_INTEGER: f64

-9007199254740991

f64.MAX_SAFE_INTEGER: f64

9007199254740991

f64.EPSILON: f64

2.2204460492503131e-16

Tree-shaking

Module-level

The compiler only compiles elements reachable from the entry file and ignores everything that remains unused. This is very similar to a JavaScript VM's behavior when running a JavaScript file, but unlike in TypeScript it also affects checking of types. Helps to reduce compilation times and binary sizes significantly.

Branch-level

In addition to module-level tree-shaking, the compiler ignores branches that it can prove won't be taken. Works with constants, built-ins that compile to a constant, expressions that can be precomputed to a constant, plus the following globals to detect specific compiler flags or features:

Constant

Description

ASC_TARGET

0 = WASM32, 1 = WASM64, 2 = JS (portable)

ASC_NO_ASSERT

Whether --noAssert is being set

ASC_MEMORY_BASE

The value of --memoryBase

ASC_OPTIMIZE_LEVEL

The value of --optimizeLevel (0-3)

ASC_SHRINK_LEVEL

The value of --shrinkLevel (0-2)

ASC_FEATURE_SIGN_EXTENSION

Whether sign extension operations are enabled

ASC_FEATURE_MUTABLE_GLOBALS

Whether mutable globals are enabled

ASC_FEATURE_NONTRAPPING_F2I

Whether non-trapping float-to-int operations are enabled

ASC_FEATURE_BULK_MEMORY

Whether bulk memory operations are enabled

ASC_FEATURE_SIMD

Whether SIMD operations are enabled

ASC_FEATURE_THREADS

Whether threads are enabled

ASC_FEATURE_EXCEPTION_HANDLING

Whether exception handling is enabled

ASC_FEATURE_TAIL_CALLS

Whether tail-calls are enabled

ASC_FEATURE_REFERENCE_TYPES

Whether reference types are enabled

For example, if a library supports SIMD but also provides a fallback:

if (ASC_FEATURE_SIMD) {
// compute with SIMD operations
} else {
// fallback without SIMD operations
}

Transforms

The compiler frontend (asc) provides hooking into the compilation process by means of transforms. Specifying --transform myTransform on the command line will load the node module pointed to by myTransform and the compiler will call the following hooks during the compilation process:

  • afterParse(parser: Parser): void Called with the parsing result of all relevant files once parsing is complete. Useful to modify the AST before it becomes compiled, for example by looking for custom decorators and injecting actual logic.

  • afterCompile(module: Module): void Called with the resulting Binaryen module before it is being emitted. Useful to modify the IR before it becomes emitted, for example to replace imports with actual functionality or to add custom sections.

Also see the transform examples. The set of hooks is intentionally minimal at this point. If you need something special, please let us know about your use case.