渲染zh-Hant

Glyphs and Latin

Glyphs and operators#

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

值流程#

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

型別形狀#

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

比較#

符號意義
精確相等與不相等
< > 順序比較
數值相等

邏輯與位元運算#

符號意義
¬且、或、互斥或、非
左移與右移

指派更新#

符號意義
運算式中唯一的指派運算子
後置遞增/遞減述句(僅限可變的 numerus

選用鏈結與非空斷言#

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

範圍#

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

字面值分隔符#

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

標點符號#

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

Latin vocabulary and structural glyphs#

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

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

三個訊號#

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

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

型別優先宣告#

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

建構C 家族慣例Faber
變數int count = 0numerus count ← 0
函式fn greet(name: String) → Stringfunctio salve(textus nomen) → textus
參數(String name)(textus nomen)

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

函式 divide(整數 a, 整數 b)  整數   {
     b  0  傳回 
    傳回 a / b
}

拉丁文行為詞彙#

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

宣告#

關鍵字角色約略對應
functio宣告具名函式或方法fndeffunction
genus宣告帶有欄位的具體型別classstruct
implendum宣告行為契約interfacetrait
typus宣告型別別名typedeftype
discretio宣告標籤聯合enumsum type

綁定與轉移#

關鍵字角色約略對應
fixum不可變綁定(寫入一次)letconst
varia可變綁定let mutvar
sit簡潔的推導型別不可變綁定let(推導型別)
redde從函式傳回值return
iace在錯誤通道上拋出錯誤throwraise
mori延後處理——尚未能表達的行為unimplemented!todo

控制流程#

關鍵字角色約略對應
si條件分支if
sin其他條件分支else if
secus其他分支else
dumWhile 迴圈while
itera迭代(值、鍵或範圍)for
elige模式比對(第一個分支優先)matchswitch
fac具錯誤復原的嘗試區塊trydo
capefac 的錯誤處理器catch

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

結構字形#

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

值流#

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

型別形狀#

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

比較與邏輯#

字形意義
精確相等與不相等——必須符合嚴格型別
< > 順序比較
¬邏輯與位元運算:且、或、異或、非

綁定慣例很重要#

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

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

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

# Runtime binding: ← attaches a value to a name
fixum numerus count ← 0
varia textus label ← "ready"
count ← count + 1

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

與主流語言比較#

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

語意工作其他語言常見寫法Faber
參數型別宣告name: Stringtextus nomen
回傳型別→ String: String textus
執行期指派x = value
相等測試==
可空性T?Option<T>T ∪ nihil
分支加上單一陳述式if (cond) return xsi cond ergo redde x
型別轉換(T)valuevalue 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 套件可以全面使用長形式,而張量核心模組則可以使用語法糖:

語法糖規範形式領域
f32f64i32u64fractus<f32>numerus<i32>寬度標記——純量數值型別
tf32tf32[4]ti64[2, 3]tensor<f32, _>tensor<f32, [4]>密集張量——t + 寬度 + 可選形狀
sf32sf32[2, 3]si64[N]sparsa<f32, _>sparsa<f32, [2, 3]>稀疏張量——s + 寬度 + 可選形狀
mf32[4, 4]mu32[3, 3]matrix<f32, [4, 4]>暫存器類別矩陣——m + 寬度 + 形狀
lf32lu32li64lista<f32>lista<u32>清單——l + 寬度
f16fractus<f16>半精度浮點寬度標記(僅限語意/配置)

一般 Faber(偏好長形式):

定值 列表<f32> values  空集

定值 張量<f32, [2, 3]> grid  空集

定值 整數<i32> narrow  7

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

定值 列表<f32> values  空集

定值 張量<f32, [2, 3]> grid  空集

定值 整數<i32> narrow  7

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

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

註解語法糖#

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

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

@ optio {
    binding = verbose,
    brevis = "v",
    longum = "verbose",
    typus = bivalens,
    ubique = verum,
    descriptio = "Enable verbose output"
}

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

@ optio verbose brevis "v" longum "verbose" typus bivalens ubique descriptio "Enable verbose output"

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

作者與規範格式化#

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

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

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

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

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

設計原則#

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

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

這個模式服務於兩個目標。第一,它降低入門門檻——新使用者可以直接撰寫 tf32[4],而不必輸入 tensor<fractus<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 — 語法糖形式的文法表格