一、結構體系
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: