渲染zh-Hant

Glyphs and Latin

Glyphs and operators#

Faber 使用符號,其中符號本身具有結構意義。以下是詞法分析器所辨識的完整來源符號清單。

值流程#

符號意義
←執行期繫結、重新指派與變更
→函式回傳型別
⇥替代退出 — 錯誤通道型別或內嵌轉換復原
∴閉包連接符 — 將閉包體與其簽名相連((a, b) → T ∴ a + b)

型別形狀#

符號意義
∷靜態型別標註(編譯期轉型)
↦執行期轉換(可能失敗的剖析/強制轉型)
∪內嵌聯集型別(T ∪ 無)

比較#

符號意義
≡ ≠精確相等與不相等
≅ ≇提升後精確相等——同值、相容的數值型別
< > ≤ ≥順序比較
≈ ≉模糊相等——依 isclose 預設容差匹配

邏輯與位元運算#

符號意義
∧ ∨ ⊻ ¬且、或、互斥或、非
⇐ ⇒左移與右移

指派更新#

符號意義
←運算式中唯一的指派運算子
⊕ ⊖後置遞增/遞減述句(僅限可變的 整數)

選用鏈結與非空斷言#

符號意義
? ?. ?[ ?(選用鏈結
! !. ![ !(非空斷言

範圍#

符號意義
‥不包含終點的範圍端點
…包含終點的範圍端點

字面值分隔符#

符號型別作用
'ascii固定的機器符號
"文字行字串
« »文字區塊字串(書名號)
`forma擷取的範本
``位元組十六進位字面值
§範本插槽"…"、«…»、 … 內的預留位置

標點符號#

符號作用
( )分組與呼叫
{ }區塊、類型 字面值或 JSON 文件
[ ]清單字面值與索引
.成員存取
,分隔符
;述句分隔符
:JSON 欄位分隔符
=結構欄位形狀(不是執行期指派)
@註解標記
#行註解

Latin vocabulary and structural glyphs#

三個訊號選擇,讓 Faber 原始碼一眼即可辨識。

Faber 有意採用三個彼此協作的訊號選擇,打造出語法形狀穩定的原始碼。讀者無須先知道程式碼將編譯至哪個目標後端,就能看出每個建構的語意角色。

三個訊號#

訊號範例角色
型別優先宣告文字 名稱、整數 aetas形狀朝向綁定——先型別,再名稱。
拉丁文行為詞函式、類型、若、傳回、定值宣告、陳述式、生命週期與行為意圖。
結構字形← → ∴ ≡ ∪ ⇥值流、型別流與結構接點——通用,永不在地化。

這三者經過設計,能彼此強化。熟悉某個語系的 Faber 讀者,可以閱讀任何語系的內容,因為字形與結構永遠不變。熟悉 Rust 後端的讀者,也仍能辨識 Faber 原始碼,因為拉丁文關鍵字與型別優先的順序,會產生獨特的視覺風格。

型別優先宣告#

Faber 在每個宣告中都將型別放在名稱之前。這與主流 C 家族語法相反,而且是刻意如此:

建構C 家族慣例Faber
變數int count = 0整數 count ← 0
函式fn greet(name: String) → String函式 salve(文字 名稱) → 文字
參數(String name)(文字 名稱)

型別優先宣告讓資料的形狀成為讀者首先看到的內容。這自然符合按語意廣度由左至右閱讀的語言——中文、印地語與阿拉伯語的宣告也遵循相同順序。

函式 divide(整數 a, 整數 b) → 整數 ∪ 無 {
    若 b ≡ 0 則 傳回 可空
    傳回 a / b
}

拉丁文行為詞彙#

Faber 使用拉丁文詞彙表示每個具有行為或文法形狀的建構。這套詞彙規模小且規則一致,取自單一的古典來源,而非多數程式語言所採用的混合詞源。

宣告#

關鍵字角色約略對應
函式宣告具名函式或方法fn、def、function
類型宣告帶有欄位的具體型別class、struct
待實作介面宣告行為契約interface、trait
型別宣告型別別名typedef、type
分支聯集宣告標籤聯合enum、sum type

綁定與轉移#

關鍵字角色約略對應
定值不可變綁定(寫入一次)let、const
變值可變綁定let mut、var
設為簡潔的推導型別不可變綁定let(推導型別)
傳回從函式傳回值return
拋出在錯誤通道上拋出錯誤throw、raise
崩潰延後處理——尚未能表達的行為unimplemented!、todo

控制流程#

關鍵字角色約略對應
若條件分支if
否則若其他條件分支else if
否則其他分支else
當While 迴圈while
遍歷迭代(值、鍵或範圍)for
選擇模式比對(第一個分支優先)match、switch
執行具錯誤復原的嘗試區塊try、do
捕捉執行 的錯誤處理器catch

拉丁文詞彙是可綁定的——它隨附於標準詞彙包,但可透過讀者語系重新映射。泰語程式設計師會看到 ถ้า 而不是 若;中文程式設計師會看到 函數 而不是 函式。詞彙並不享有特權;只有文法不變。

結構字形#

行為詞彙使用拉丁文,而結構意義使用通用字形。這些字形永不在地化,也不會在不同轉譯中改變意義。無論關鍵字以哪種人類語言呈現,它們都是讓 Faber 原始碼保持可辨識的視覺錨點。

值流#

字形意義
←執行期綁定、重新指派與變異——唯一的指派運算子
→函式回傳型別宣告
⇥替代出口:錯誤通道型別或行內轉換復原
∴閉包連接符 — 將閉包體與其簽名相連

型別形狀#

字形意義
∷靜態型別標註——對值型別的編譯期斷言
↦執行期轉換——可能失敗的解析或強制轉型
∪行內聯合型別——連接兩個型別(例如 T ∪ 無)

比較與邏輯#

字形意義
≡ ≠ ≢精確相等與不相等——必須符合嚴格型別
≅ ≇提升後精確相等——數值寬度合併後精確比較
≈ ≉模糊相等——依 isclose 預設容差匹配
< > ≤ ≥順序比較
∧ ∨ ⊻ ¬邏輯與位元運算:且、或、異或、非

綁定慣例很重要#

有一個字形選擇值得特別注意,因為它是新讀者最常混淆的地方:

字形角色用於
←執行期流動執行時的初始綁定、重新指派與變異
=結構形狀常值中的欄位名稱與宣告中繼資料——不是執行期儲存

多數語言會重載 =,同時表示「在型別中定義此欄位」與「將執行期值放入此變數」。Faber 將這兩項工作分開。每個 ← 都是即時資料流;每個 Type { … } 中的 = 都表示 類型 的欄位配置。

# Runtime binding: ← attaches a value to a name
定值 整數 count ← 0
變值 文字 label ← "ready"
count ← count + 1

# Structural shape: = defines field values inside a literal
定值 _ p ← Point {
    x = 10,
    y = 20
}

與主流語言比較#

下表展示常見程式語言模式如何對應至 Faber 的三訊號系統。Faber 欄位會針對每個不同的語意工作使用不同的字形或關鍵字——不進行重載。

語意工作其他語言常見寫法Faber
參數型別宣告name: String文字 名稱
回傳型別→ String、: String→ 文字
執行期指派x = value←
相等測試==≡
可空性T?、Option<T>T ∪ 無
分支加上單一陳述式if (cond) return x若 cond 則 傳回 x
型別轉換(T)value、value as Tvalue ∷ T
轉換(可能失敗)try_into()value ↦ T

參考資料#

  1. EBNF 文法——完整的字形與關鍵字清單
  2. examples/corpus/——包含所有關鍵字的語言語料庫,共有 292 個範例檔案
  3. examples/corpus/operatores/——運算子與字形範例
  4. Commandments——維持這些訊號的九項設計法則

Canonical vs sugar surfaces#

多個可解析表面,共用一個語意形狀。

Faber 設計中反覆出現一種模式:語言為每個建構定義一種規範拼寫,但也接受多種語意相同的語法糖拼寫。編譯器不偏好其中任何一種——兩者都會解析為相同的 AST 節點。格式化工具會根據上下文與模式決定要輸出哪一種拼寫。

規則:語法糖拼寫在語意上等同於長形式。 多個表面會解析為相同的 HirAnnotation 或型別節點。 faber format --canonical 偏好規範拼寫;作者模式則保留作者所寫的語法糖。

數值型別語法糖#

數值型別具有長形式的規範拼寫,以及精簡的語法糖形式。 選擇以模組為單位,而不是以儲存庫為單位——CLI 套件可以全面使用長形式,而張量核心模組則可以使用語法糖:

語法糖規範形式領域
tf32、tf32[4]、ti64[2, 3]張量<f32, _>、張量<f32, [4]>密集張量——t + 寬度 + 可選形狀
sf32、sf32[2, 3]、si64[N]稀疏<f32, _>、稀疏<f32, [2, 3]>稀疏張量——s + 寬度 + 可選形狀
mf32[4, 4]、mu32[3, 3]矩陣<f32, [4, 4]>暫存器類別矩陣——m + 寬度 + 形狀
lf32、lu32、li64列表<f32>、列表<u32>清單——l + 寬度

一般 Faber(偏好長形式):

入口 {
    定值 列表<f32> values ← 空集
    定值 張量<f32, [2, 3]> grid ← 空集
    定值 i32 narrow ← 7
}

數值模組(偏好語法糖):

入口 {
    定值 lf32 values ← 空集
    定值 tf32[2, 3] grid ← 空集
    定值 i32 narrow ← 7
}

語法糖僅限型別位置。名為 f32、tf32 或 mf32 的值識別字維持不變——編譯器只會在它們出現在型別位置時,將其解讀為語法糖。若檔案一致使用語法糖,應在檔案頂端說明一次:

# STYLE: numeric sugar (tf32, mf32, sf32, lf32, lu32)

註解語法糖#

Faber 註解遵循與數值型別相同的雙表面模型。 註解是附加至宣告的編譯器管理中繼資料——例如 CLI 選項定義的 @ 選項,或非同步函式的 @ 未來。

規範形式:具有明確欄位名稱的花括號記錄:

@ 選項 {
    binding = verbose,
    簡 = "v",
    詳 = "verbose",
    型別 = 布林,
    全局 = 真,
    描述 = "Enable verbose output"
}

語法糖形式:位置引數與具名別名:

@ 選項 verbose 簡 "v" 詳 "verbose" 型別 布林 全局 描述 "Enable verbose output"

兩種形式都會產生相同的 HirAnnotation 記錄。規範形式明確且便於自我說明;語法糖形式則適用於欄位順序已廣為人知的常用註解,因此更為精簡。 faber format --canonical 偏好花括號記錄;作者模式則保留作者選擇的形式。

作者與規範格式化#

faber format 指令以兩種模式運作,對應規範與語法糖原則:

模式指令輸入輸出
作者faber format已解析的 AST + 開頭雜項保留 # 註解、空白行與語法糖拼寫的 Faber 原始碼
規範faber format --canonical已分析的 HIR + TypeTable正規化的 Faber——無註解、使用規範拼寫、不含語法糖

兩種模式都會經過編譯器完整的前半部流程(詞法分析、解析;規範模式另含分析)。無效原始碼會產生編譯器診斷——格式化工具不會默默格式化損壞的輸入。

兩種模式共同遵循的主要規則:

  • 四個空格縮排
  • Stroustrup 大括號:開啟的 { 與控制標頭位於同一行
  • 作者模式保留空白行的存在與否,但會將多於一個的連續空白行折疊
  • 作者模式不會插入來源中不存在的空白行
  • 規範模式會將型別拼寫正規化為長形式、將張量語法糖正規化為規範形式,並將註解正規化為花括號記錄
  • 規範模式會對可為空的聯集輸出 T ∪ 無,並對可選參數輸出 可選

設計原則#

規範與語法糖模式會出現在多個地方,是因為這是一項刻意的設計原則,而不是一組零散的一次性便利功能:

領域規範語法糖
張量型別張量<f32, [4]>tf32[4]
註解@ 選項 { binding = verbose }@ 選項 verbose ...
格式化faber format --canonicalfaber format(作者模式)
讀者語系拉丁文(la)任一語系套件

這個模式服務於兩個目標。第一,它降低入門門檻——新使用者可以直接撰寫 tf32[4],而不必輸入 張量<f32, [4]>。第二,它讓規範語言保持明確無歧義——當精確度很重要時,長形式會清楚表達其確切含義。格式化工具則在兩者之間搭起橋樑:作者撰寫語法糖,審閱者可以要求規範形式,而 CI 可以強制執行其中任一形式。

參考資料#

  1. radix/docs/design/numeric-type-sugar.md — 完整語法糖系列、拼寫偏好
  2. radix/docs/design/annotation-sugar.md — 雙表面註解模型
  3. radix/docs/design/faber-canonical-surface.md — 作者與規範格式政策
  4. faber/docs/EBNF.md — 語法糖形式的文法表格