一、结构体系
1.编译
编译器的结构相对保守。
提供源文件,其文本被标记化并解析为抽象语法树。 这里执行语法级检查。
一旦解析了所有引用的源文件,就构造一个程序并从AST初始化。 在这里进行合理性检查。 然后,程序及其元素充当代码生成中的中间表示,包含解析类型,标识符,属性访问等所需的所有信息。
然后,执行将程序元素编译到Binaryen模块。 在此处执行对单个语句和表达式的最终检查。 默认情况下,编译从入口文件导出开始,然后遍历可访问的程序元素(也称为“树抖动”)。 在编译器级别上这样做可以提供显着的速度优势,因为根本不编译死代码,但也有缺陷,即没有完全检查死代码。 然而,指定 --noEmit --noTreeShaking 会检查所有内容而不生成代码。
然后可以验证、优化生成的模块,并以Binaryen的各种格式输出(textual .wat,binary .wasm,asm.js .js)。
2.API
编译器本身导出一个相对低级的类C语言API,它提供了在可互换的JS / WASM环境中执行编译所需的一切。
低级API由asc(节点的编译器前端)使用,它也以编程方式公开其CLI API。
3.标准库
虽然尚未完全理解,但标准库组件位于std文件夹中,有两种版本,用asc编译的针对WebAssembly的汇编标准库和tsc编译的针对JavaScript的可移植标准库。
可移植标准库基本上以与汇编脚本兼容的方式声明环境中已经存在的内容,而汇编标准库在AssemblyAs for WebAssembly中重新实现了相同的功能。
二、内置INS
为了提供对本机WebAssembly操作的直接(编译到操作码)访问,在全局范围中提供了以下函数以及一些类似TS / JS的常量:
1.上下文敏感的常量
- NaN:
f32 | f64
NaN (not a number) 作为32位或64位浮点数,具体取决于上下文。 编译为常量。
- Infinity:
f32 | f64
正无穷大为32位或64位浮点数,具体取决于上下文。 编译为常量。
2.编译时类型检查
- isInteger<
T
>(value?:T
):bool 测试指定的类型或表达式是否为整数类型而不是引用。 编译为常量。
- isFloat<
T
>(value?:T
):bool 测试指定的类型或表达式是否为float类型。 编译为常量。
- isSigned <
T
>(value?:)T
:bool 测试指定的类型或表达式是否可以表示负数。编译为常量。
- isReference <
T
>(value?:)T
:bool 测试指定的类型或表达式是否为引用类型。编译为常量。
- isString <
T
>(value?:)T
:bool 测试指定的类型或表达式是否可以用作字符串。编译为常量。
- isArray <
T
>(value?:)T
:bool 测试指定的类型或表达式是否可以用作数组。编译为常量。
- isFunction <
T
>(value?:)T
:bool 测试指定的类型或表达式是否为函数类型。编译为常量。
- isNullable <
T
>(value?:)T
:bool 测试指定的类型或表达式是否为可为空的引用类型。编译为常量。
- isDefined(expression :)
*
:bool 测试指定的表达式是否解析为已定义的元素。编译为常量。
- isConstant(expression :)
*
:bool 测试指定的表达式是否计算为常量值。编译为常量。
- sizeof <
T
>():usize 确定指定核心或类类型的字节大小。编译为常量。
- offsetof <
T
>(fieldName?:)string
:usize 确定给定类类型中指定字段的偏移量。 如果省略了字段名,则返回类类型的结束偏移量。 编译为常量。
- alignof <
T
>():usize 确定指定底层核心类型的对齐方式(log2)。编译为常量。
注意,constantOffset参数必须是编译时常量(const全局或本地)。 同样,fieldName参数必须是字符串。
注意,每当编译器发现常量条件时,它将自动删除未获取的分支,而不会尝试编译它们。例如,如果一个泛型函数要同时处理整数和字符串,并且只有几个不同的语句,那么可以使用if-then-else语句上带有常量条件的编译时类型检查,使其根据实际类型参数的不同部分表现不同:
1 function doSomething<T>(a: T): T { 2 if (isString<T>()) { 3 ... // eliminated if T is not a string 4 } else { 5 ... // eliminated if T is a string 6 } 7 }
3.数学
- isNaN<
T = f32 | f64
>(value:T
):bool 测试32位或64位浮点数是否为NaN。
- isFinite<
T = f32 | f64
>(value:T
):bool 测试32位或64位浮点数是否有限,即不是NaN或+/-无穷大。
- clz<
T = i32 | i64
>(value:T
):T 执行符号无关的计数,在32位或64位整数上执行零位操作。 如果值为零,则认为所有零位都是前导的。
- ctz<
T = i32 | i64
>(value:T
):T 在32位或64位整数上执行符号无关的计数跟踪零位操作。 如果值为零,则将所有零位视为尾随。
- popcnt<
T = i32 | i64
>(value:T
):T 对32位或64位整数执行一位操作的符号不可知计数。
- rotl<
T = i32 | i64
>(value:T
, shift:T
):T 对32位或64位整数执行符号无关的左旋转操作。
- rotr<
T = i32 | i64
>(value:T
, shift:T
):T 对32位或64位整数执行符号无关的右旋操作。
- abs<
T = i32 | i64 | f32 | f64
>(value:T
):T 计算整数或浮点数的绝对值。
- max<
T = i32 | i64 | f32 | f64
>(left:T
, right:T
):T 确定两个整数或浮点数的最大值。 如果任一操作数为NaN,则返回NaN。
- min<
T = i32 | i64 | f32 | f64
>(left:T
, right:T
):T 确定两个整数或浮点数的最小值。 如果任一操作数为NaN,则返回NaN。
- ceil<
T = f32 | f64
>(value:T
):T 在32位或64位浮点上执行向上取整操作。
- floor<
T = f32 | f64
>(value:T
):T 在32位或64位浮点上执行向下取整操作。
- copysign<
T = f32 | f64
>(x:T
, y:T
):T 根据x的大小和y的符号组成32位或64位浮点数。
- nearest<
T = f32 | f64
>(value:T
):T 对32位或64位浮点数四舍五入。
- reinterpret<
T = i32 | i64 | f32 | f64
>(value:*
):T 将指定值的位重新解释为类型T.有效的重新解释是 u32/i32 与 f32 和 u64/i64 与 f64。
- sqrt<
T = f32 | f64
>(value:T
):T 计算32位或64位浮点的平方根。
- trunc<
T = f32 | f64
>(value:T
):T 向32位或64位浮点数的最接近的整数舍入为零。
4.内存访问
- load<
T
>(ptr:usize
, constantOffset?:usize
):T 从内存中加载指定类型的值。 相当于在其他语言中取消引用指针。
- store<
T
>(ptr:usize
, value:T
, constantOffset?:usize
):void 将指定类型的值存储到内存中。 相当于在分配值时取消引用其他语言中的指针。
5.控制流
- select<
T
>(ifTrue:T
, ifFalse:T
, condition:bool
):T 根据条件选择两个预先评估的值中的一个。
- unreachable():
* 发出无法访问的操作,导致执行时出现运行时错误。 语句和任何类型的表达式。
6.主机操作
- memory.size():
i32 以页为单位返回内存的当前大小。 一页是64kb。
- memory.grow(value:
i32
):i32 通过给定的无符号页面增量生成线性内存。 一页是64kb。 以页为单位返回先前的内存大小,或者在失败时返回-1。 请注意,调用内存管理器所在的memory.grow可能会破坏它。
7.其他
- parseInt(str:
string
, radix?:i32
):i64 将字符串解析为64位整数。 与JS中的NaN不同,在无效输入上返回0。
- parseFloat(str:
string
):f64 将字符串解析为64位浮点数。 在无效输入上返回NaN。
- changetype<
T
>(value:*
):T 将值的类型更改为另一个值。 用于将类实例转换为其指针值,反之亦然。
- assert<
T
>(isTrueish:T
, message?:string
):T 如果断言的值不是true-ish,则捕捉,否则返回不可空值。
- unchecked(expr:
*
):* 明确请求对提供的表达式不进行边界检查。 对数组访问很有用。
- call_indirect<
T
>(target:u32
, ...args:*[]
):T 发出call_indirect指令,通过索引使用指定的参数调用函数表中的指定函数。 如果参数与被调用函数不匹配,则会导致运行时错误。
- instantiate<
T
>(...args:*[]
):T 使用指定的构造函数参数实例化T的新实例。
8.修饰符
以下特定于WebAssembly的运算符可用于注释非TS行为:
- @global 将元素添加到全局范围。
- @inline 强制函数内联。
- @external([moduleName:
string
,] elementName:string
) 更改声明的全局或函数的外部名称。 - @operator(token:
string
) 注释二元运算符重载。- @operator.binary(token:
string
) 与@operator一样 - @operator.prefix(token:
string
) 注释一元前缀运算符重载。 - @operator.postfix(token:
string
) 注释一元后缀运算符重载。
- @operator.binary(token: