渲染zh-Hant

Grammar

Faber 原始碼是由驅動程式在詞法分析前處理的純文字。選用的 TOML 前置資料不是 token grammar 的一部分。本文是 Faber 語言的正式文法與規格說明;可執行的參考程式位於公開的 ../examples/corpus/,工具可從磁碟載入參考套件。

---

程式結構#

Faber 檔案可選擇以 +++ TOML 前置資料開始,之後接著程式本體。前置資料只由編譯器驅動程式解析,不會被當作 Faber 陳述式解析。

fabFile       := frontmatter? program
frontmatter   := '+++' NEWLINE tomlBody NEWLINE '+++' NEWLINE?
program       := statement*
statement     := importDecl | varDecl | funcDecl | genusDecl | implendumDecl
               | typeAliasDecl | enumDecl | discretioDecl
               | ifStmt | whileStmt | iteraStmt
               | eligeStmt | discerneStmt | guardStmt | curaStmt | facBlockStmt
               | returnStmt | breakStmt | continueStmt | noopStmt | throwStmt
               | assertStmt | outputStmt | adStmt | incipitStmt
               | incipietStmt | extractStmt
               | probandumDecl | probaStmt | blockStmt | incDecStmt | exprStmt
blockStmt     := '{' statement* '}'

檔案前置資料(+++#

前置資料若存在,必須在第 1 行以完全相同的 +++ 開始。後續去除前後空白後仍完全等於 +++ 的行會結束區塊。結束分隔符後的位元組就是 Faber program。空白主體是合法的空程式。

前置資料是通用 TOML 文件。作者可附加任意 metadata key;工具會透過 accessor 讀取 groupsectio[probanda] 等已知 key。套件模式仍以 faber.toml[package][paths][build] 為準;衝突值會被拒絕。

+++
group = "exempla.directiva"
sectio = "smoke"
+++

入口 {}

行首 § 檔案指令已移除。檔案 metadata 請放在 +++ 前置資料中。引號字串內的 § 仍是字串範本洞(見「呼叫與成員存取」)。

---

宣告#

變數#

varDecl      := ('定值' | '變值') typeAnnotation IDENTIFIER (('←' expression) | ('↤' assignment inlineRecovery?))?
sitDecl      := '設為' IDENTIFIER ('←' expression)?
arrayDestruct := ('定值' | '變值') arrayPattern '←' expression
objectDestruct := ('定值' | '變值') objectPattern '←' expression
  • 定值 建立不可變 binding(只能寫入一次):可以不帶初始值宣告,之後恰好指定一次,指定後即凍結。變值 建立可重新指定的 binding,類似 let
  • 初始化值能決定型別時,型別標註可使用 _定值 _ name ← value
  • 設為 name ← value定值 _ name ← value 的語法糖(推導型別的不可變區域量)。
  • 設為 name(沒有初始值)是 定值 _ name 的語法糖,表示延後初始化的推導型別不可變量;任何讀取前都必須恰好指定一次。
  • 延後初始化:定值 整數 x設為 x 宣告未初始化的不可變槽位。任何讀取前都必須恰好指定一次;第二次指定會被拒絕。確定性指定分析(語意階段 3a)會強制執行這項規則。

函式#

funcDecl     := '函式' IDENTIFIER genericParams? '(' paramList ')' funcModifier* returnClause? alternateExitClause? blockStmt?
paramList    := (parameter (',' parameter)*)?
genericParams := '<' genericParam (',' genericParam)* '>'
genericParam  := IDENTIFIER | '尺寸' IDENTIFIER
typeArgs      := '<' typeAnnotation (',' typeAnnotation)* '>'
parameter    := ('從' | '傳入' | '取自')? '其餘'? typeAnnotation IDENTIFIER '可選'? ('作為' IDENTIFIER)? ('或取' expression)?
funcModifier := '引數' IDENTIFIER | '管理' IDENTIFIER ('作為' IDENTIFIER)? | '錯誤' IDENTIFIER | '出口' (IDENTIFIER | NUMBER) | '不變' | '拋出' | '選項' IDENTIFIER
returnClause := '→' typeAnnotation
alternateExitClause := '⇥' typeAnnotation
stmtBodyJoint  := '則'
clausuraJoint  := '∴'
clausuraExpr   := compactClausuraExpr | legacyClausuraExpr
compactClausuraExpr := clausuraSignature clausuraJoint (expression | closureFacBlock)
clausuraSignature := (clausuraParam | '(' clausuraParams? ')') returnClause? alternateExitClause?
closureFacBlock := '執行' blockStmt catchClause?
legacyClausuraExpr := '閉包' clausuraParams? ('→' typeAnnotation)? (':' expression | blockStmt)
clausuraParams := clausuraParam (',' clausuraParam)*
clausuraParam  := typeAnnotation IDENTIFIER
  • 宣告正常成功型別。具有函式主體但沒有 的函式是效果限定(空值),且不得包含 傳回。語句主體閉包(執行 { ... } 或舊式區塊主體)若要使用 傳回,也必須明確寫出 → T;運算式主體閉包可由運算式推導結果。
  • 宣告可復原的替代出口型別。它可出現在 → T 後,也可單獨出現在效果限定的可失敗函式或閉包上。使用逃逸 拋出 的閉包必須宣告自己的 ⇥ E,不能繼承外層函式的錯誤通道。
  • 在宣告 的函式內,可失敗呼叫(→ T ⇥ E)會直接傳播到函式的替代出口,不需要 執行/捕捉 包裹;它會降級為 Rust ?。閉包仍必須宣告自己的 ,因為外層函式的錯誤通道不會跨越閉包邊界。
  • 執行 { ... } 捕捉 err { ... } 是標準的一次性區域可復原錯誤邊界。
  • 參數前綴:(讀取)、傳入(變更)、取自(消費)。
  • 名稱後標記:可選(自願/可選提供)。其餘 標記剩餘參數。管理 NAME ('作為' LOCAL) 宣告配置器需求;LOCAL 是函式主體內的別名。

宣告錯誤通道型別。它可出現在 → T 之後,也可獨立出現在 effect-only 的可失敗函式或閉包上。使用逃逸 拋出 的閉包必須宣告自己的 ⇥ E,不能繼承外層函式的錯誤通道。執行 { ... } 捕捉 err { ... } 是單次區域復原錯誤邊界。 只用於單一語句主體; 只用於 compact clausura,兩者不是別名。

類別#

genusDecl    := '抽象'?'類型' IDENTIFIER typeParams? ('子' IDENTIFIER)? ('實作' IDENTIFIER (',' IDENTIFIER)*)? '{' genusMember* '}'
genusMember  := annotation* (fieldDecl | methodDecl)
fieldDecl    := '靜態'? '綁定'? typeAnnotation IDENTIFIER '可選'? ('=' expression)?
methodDecl   := '函式' IDENTIFIER '(' paramList ')' funcModifier* returnClause? alternateExitClause? blockStmt?

註解#

annotation            := '@' annotationName annotationBody?
annotationName        := IDENTIFIER | '公開' | '保護' | '私有' | '未來' | '游標'
                        | '標籤' | '僅限' | '略過' | '測量'
annotationBody        := bracedAnnotation | annotationArgs
bracedAnnotation      := '{' annotationFieldList? '}'
annotationFieldList   := annotationField (',' annotationField)* ','?
annotationField       := IDENTIFIER '=' (expression | typeAnnotation)
cliProgramAnnotation := '@' 'cli' STRING
imperiumAnnotation := '@' 'imperium' STRING
optioAnnotation    := '@' 'optio' IDENTIFIER optioModifier*
optioModifier      := '短' STRING | '長' STRING | '型別' typeAnnotation
                    | '說明' STRING | '全域' | '或取' expression
operandusAnnotation := '@' '位置引數' ('其餘')? typeAnnotation IDENTIFIER operandusModifier*
operandusModifier  := '說明' STRING | '全域' | '或取' expression
annotationArgs     := (STRING | IDENTIFIER | expression)+
annotatioMarker    := '@' 'annotatio' ( '{' annotatioFieldList? '}' )?
annotatioFieldList := annotatioField (',' annotatioField)* ','?
annotatioField     := 'target' '=' annotatioTarget
annotatioTarget    := '函式' | STRING | IDENTIFIER
contractApplication := '@' IDENTIFIER ( '{' annotationFieldList? '}' )?
jsonGenusAnnotation := '@' 'json'
jsonFieldAnnotation := '@' 'json' '{' '名稱' '=' STRING '}'

@ annotatio 將頂層 genus 標記為編譯期註解契約。普通 genus 不是註解 schema。應用程式使用 @ ContractName { field = constant },並透過本地宣告或匯入的檔案介面匯出解析。解析後的應用會降級為 HirAnnotation,其中含有 contract_id: Some(DefId) 與常數欄位值。v1 的附加目標僅限 functio;載荷純量型別為 textusnumerusfractusbivalens,可透過 sponteT ∪ nihil 表示可選。編譯器不提供自有的 @ web、controller 或 route 族。

JSON genus:@ json 套用於 genus 時,是編譯器擁有的資料模型契約,不是通用註解 schema。欄位必須是 JSON 安全型別:textusasciinumerusfractusbivalensinstansnihillista<T>tabula<textus, T>、可空的 T ∪ nihil,或另一個 @ json genus。欄位中 @ json { nomen = "wire_name" } 會變更 value ↦ valorvalue ↦ jsonjson ↦ Genus 輸出的物件鍵。JSON 文字仍是 Norma 的線上操作,例如 json.pange(value ↦ json)

  • @ radix 保留給編譯器擁有的 metadata。歷史上的詞幹意義已退役;形態學仍是來源命名規範,不是編譯器產生的變位。接受的形式是套用在頂層函式上的 @ radix lane "air""mir""hir-direct",用於明確的編譯器 lane 路由;不支援的 lane/target 組合會以診斷拒絕,不會靜默忽略。
  • @ verte 定義程式碼生成轉換(方法名稱或範本)。
  • @ nondum [TARGET] ["REASON"] 表示宣告存在於介面中,但目前目標不可用。
  • @ cli "NAME"incipit 入口標記為 CLI 程式。
  • @ imperium "NAME" 將函式標記為 CLI 命令入口。
  • @ optio NAME ... 定義 CLI 選項;布林旗標使用 型別 布林
  • @ operandus [ceteri] TYPE NAME ... 定義 CLI 位置引數。
  • @ futura 標記非同步函式;@ cursor 標記產生器。
  • @ publica@ privata 會被解析,但不會被強制執行;編譯器會發出 WARN012(裝飾性可見性),避免作者誤以為存在存取控制。
  • @ protecta 保留並會以語意診斷拒絕;它不代表套件、子類別或同檔案可見性。
  • sub = 延伸;implet = 實作。
  • generis = 靜態;nexum = 綁定或屬性。

介面#

implendumDecl   := '待實作介面' IDENTIFIER typeParams? '{' implendumMethod* '}'
implendumMethod := annotation* '函式' IDENTIFIER '(' paramList ')' funcModifier* returnClause? alternateExitClause?

待實作介面 是只含簽章的方法契約,供 實作 使用。匯入 namespace 以 .fab 檔案為邊界;匯出的宣告位於檔案頂層。

型別別名#

typeAliasDecl := '型別' IDENTIFIER genericParams? '=' typeAnnotation

列舉與標籤聯集#

enumDecl   := '列舉' IDENTIFIER '{' enumMember (',' enumMember)* ','? '}'
enumMember := IDENTIFIER ('=' ('-'? NUMBER | STRING))?
discretioDecl := '分支聯集' IDENTIFIER typeParams? '{' variant (',' variant)* ','? '}'
variant       := IDENTIFIER ('{' variantFields '}')?
variantFields := (typeAnnotation IDENTIFIER (',' typeAnnotation IDENTIFIER)*)?

識別符命名#

混合大小寫且首字母小寫的名稱在語法上接受,但不是 Faber 語言、標準函式庫、主機路由或編譯器 intrinsic API 的偏好。優先使用單一字詞;單一字詞不足以承載語意時,才在少數情況使用 snake_case。若兩種形式都不合適,除非方法不可或缺,否則它可能不屬於核心表面。標準函式庫的編解碼在各模組使用機械動詞三件組 pange / solve / tempta;公開文字函式庫是 norma:chorda

匯入#

importDecl     := importRecord | importSugar
importRecord   := '匯入' '{' importFieldList? '}'
importFieldList := importField (',' importField)* ','?
importField    := importSourceField | importVisibilityField | importNameField
                | importAliasField | importWildcardField
importSourceField := '取自' '=' STRING
importVisibilityField := '可見性' '=' visibility
importNameField := '名稱' '=' IDENTIFIER
importAliasField := '作為' '=' IDENTIFIER
importWildcardField := '全部' '=' IDENTIFIER
importSugar    := '匯入' '取自' STRING visibility? (namedImport | wildcardImport)?
visibility    := '私有' | '公開'
namedImport   := IDENTIFIER ('作為' IDENTIFIER)?
wildcardImport := '*' '作為' IDENTIFIER
匯入取自 "hono" 私有 Hono
匯入取自 "norma:chorda"
匯入 { 取自 = "norma:json/solve", 作為 = solve_mod }
匯入取自 "./types" 公開 User

未指定可見性時預設為 私有。未指定 binding 時,若最後一段路徑是合法且不衝突的識別符,就使用該名稱。

---

型別#

typeAnnotation := ('從' | '傳入')? baseType ( '∪' typeAnnotation )*
baseType       := holeType | functionType | qualifiedType typeParams? | '(' typeAnnotation ')'
holeType       := '_' | '∪'
qualifiedType  := IDENTIFIER ('.' IDENTIFIER)*
functionType   := '(' typeList? ')' '→' typeAnnotation alternateExitClause?
typeList       := typeAnnotation (',' typeAnnotation)*
typeParams     := genericParams

陣列寫成 列表<T>;不接受 postfix T[]傳入 是型別前綴的所有權標記。T ∪ 無 是標準 nullable 型別形式。可選 是宣告標記,不是型別前綴。限定型別路徑必須透過匯入 namespace 解析。

函式 篩選((T) → 布林 預測) → 列表<T>
函式 組合((A) → B f, (B) → C g) → (A) → C
函式 套用((整數) → 整數 ⇥ 文字 op, 整數 n) → 整數 ⇥ 文字

原始型別#

Faber意義
文字Unicode 字串
ascii僅 ASCII 的字串
forma擷取的範本與參數
整數整數,預設 i64
模數<W>無號模數字,算術以 2^W 取模
小數浮點數,預設 f64
布林布林值
null
空值void
永不never
未知unknown
位元組bytes

大小型別使用寬度標記。整數 / 小數 可省略寬度而分別代表 i64 / f64模數<W> 是獨立語意家族,不會與 整數<W> 隱式混用。

泛型集合#

Faber意義
列表<T>陣列
表格<K,V>map
副本<T>set
承諾<T>promise
游標<T>iterator
tensor<T, Figura>具有靜態形狀的密集同質緩衝區
vector<T, N>固定寬度的數值向量
matrix<T, [R, C]>恰有兩個靜態維度的數值矩陣
atomic<T>儲存敏感的 atomic cell
sparsa<T, Figura>具有靜態形狀的稀疏同質緩衝區

Figura := _、自然數、識別符或 [ 形狀列表 ];空 [] 表示 rank-0。裸 tensor<T> 不完整:rank-0 使用 tensor<T, []>,推導形狀使用 tensor<T, _>

空值 用於 tensor<T, []> 會產生 rank-0 tensor(含一個預設初始化的元素槽)。空值 用於任意形狀的 sparsa<T, Figura> 會產生沒有儲存項目的全零稀疏 tensor。matrix<T, Figura> 必須恰好有兩個維度;裸 matrix<T> 以及一維或三維形狀都會被拒絕。

atomic<T> 在 v1 只接受 i32u32;atomic cell 不可與元素型別互換,必須使用 loadstoreexchangecompare_exchange 接收者方法。多維 tensor 使用 creastructa 建構。Type(...) 不是建構形式:vector<f32, 4>(...)matrix<f32, [2, 2]>(...)tensor<f32, [2, 2]>(...) 以及 numerus("42") 等純量形式都會被拒絕。請使用 value ↦ Type、具名函式庫建構子或 Genus { field = value } 記錄。

Tensor 的索引/形狀 intrinsic 槽(accipepondeformacreastructa)在呼叫點接受符合 lista<numerus>&[i64] 執行期邊界的整數列表,例如 GPU thread id 可使用 lista<u32>,但不可使用 lista<u64>。這是限定於這些槽位的結構性例外,不會放寬有號與無號數值格。

值聯集使用 inline T ∪ U(可空形式:T ∪ 無);標籤聯集使用 分支聯集副本.unio() 是集合方法,不是型別建構子。vacua 是上下文相關的空集合標記,必須搭配明確集合型別。

型別糖#

型別糖只在型別位置有效,與長格式語意相同。寬度標記為 i8i16i32i64u8u16u32u64f16f32f64lf32 等表示列表,tf32[2, 3] 表示 tensor,sf32[2, 3] 表示 sparsa,vf32[4] 表示 vector,mf32[4, 4] 表示 matrix。matrix 必須指定兩個維度。模數<W> 沒有糖,請使用完整形式。

---

控制流程#

條件式#

ifStmt     := '若' expression arm ('否則若' ifStmt | elseClause)?
elseClause := '否則' elseArm
arm        := (blockStmt | stmtBodyJoint statement) catchClause?
elseArm    := (blockStmt | stmtBodyJoint statement) catchClause?

用於單一語句主體,例如 則 傳回則 拋出則 崩潰則 靜默靜默 是明確 no-op。

迴圈#

whileStmt  := '當' expression (blockStmt | stmtBodyJoint statement) catchClause?
iteraStmt  := '遍歷' (('取自' | '從') expression | '自' expression) ('定值' | '變值') IDENTIFIER (blockStmt | stmtBodyJoint statement) catchClause?

遍歷 取自 ... 定值 是 for-of;遍歷 從 ... 定值 是 for-in;遍歷 自 range 定值 i 是範圍迭代。 屬於範圍運算式。

Switch / Match#

eligeStmt    := '選擇' expression '{' eligeCase* defaultCase? '}' catchClause?
eligeCase    := '分支' expression (blockStmt | stmtBodyJoint statement)
defaultCase  := '預設' (blockStmt | stmtBodyJoint statement)
discerneStmt := '比對' '全部'? discriminants '{' variantCase* defaultCase? '}'
discriminants := expression (',' expression)*
variantCase  := '分支' patterns (blockStmt | stmtBodyJoint statement)
patterns     := pattern ((',' | '且') pattern)*
pattern      := '_' | literal | (IDENTIFIER patternBind?)
patternBind  := ('作為' IDENTIFIER) | (('定值' | '變值') patternBinding (',' patternBinding)*)
patternBinding := IDENTIFIER ('作為' IDENTIFIER)?

守衛與資源#

guardStmt   := '守衛' '{' guardClause+ '}'
guardClause := '若' expression (blockStmt | stmtBodyJoint statement)
curaStmt    := '資源' STRING ('定值' | '變值') typeAnnotation IDENTIFIER blockStmt catchClause?

解構擷取與控制轉移#

extractStmt   := '取自' expression ('定值' | '變值') extractFields
extractFields := extractField (',' extractField)* (',' restField)? | restField
extractField  := IDENTIFIER ('作為' IDENTIFIER)?
restField     := '其餘' IDENTIFIER
returnStmt   := '傳回' expression?
breakStmt    := '中斷'
continueStmt := '繼續'
noopStmt     := '靜默'

---

錯誤處理#

throwStmt   := ('拋出' | '崩潰') expression ['若' expression]
catchClause := '捕捉' IDENTIFIER blockStmt
assertStmt  := '斷言' expression ('secus' expression)?

捕捉 可附加於結構化語句與條件分支,不可附加於任意裸區塊。執行 { ... } 捕捉 err { ... } 是標準的區域復原錯誤邊界。嘗試最後 是舊語法並會被遷移診斷拒絕。拋出 可復原;崩潰 是致命錯誤。拋出 value 若 condition 會在解析時展開為條件式。

---

運算式#

運算子(由低至高)#

expression := assignment
assignment := ternary ('←' assignment | '↤' assignment inlineRecovery?)?
incDecStmt := place ('⊕' | '⊖')
ternary    := or (('?' expression ':' | '如此' expression '否則') ternary)?
or         := and (('或') and)*
and        := equality (('且') equality)*
equality   := comparison (('≡' | '≠' | '≈' | '≉' | '是' | '非' '是') comparison)*
comparison := bitwiseOr (('<' | '>' | '≤' | '≥' | '內含' | '之間') bitwiseOr)*
bitwiseOr  := bitwiseXor ('∨' bitwiseXor)*
bitwiseXor := bitwiseAnd ('⊻' bitwiseAnd)*
bitwiseAnd := shift ('∧' shift)*
shift      := range (('⇐' | '⇒') range)*
range      := additive (('‥' | '…' | '之前' | '直到') additive ('每' additive)?)?
additive   := multiplicative (('+' | '-') multiplicative)*
multiplicative := coalesce (('*' | '/' | '%') coalesce)*
coalesce   := unary ('或取' velRhs)*
velRhs     := unary (('‥' | '…' | '之前' | '直到') unary ('每' unary)?)?
unary      := ('-' | '¬' | '非' | '讓出' | '虛構') unary | cast
cast       := call ('∷' typeAnnotation | conversio)*
conversio  := '↦' typeAnnotation typeParams? inlineRecovery?
inlineRecovery := '⇥' unary

是定向轉換賦值:先求右側值,透過 路徑轉換為左側位置的靜態型別,再賦值。 內聯恢復僅在 上合法,不允許接在 之後。

不在上述運算子文法中,永遠只表示 clausura joint。 是編譯期靜態型別標註; 是會執行實際解析或轉換的執行期運算子。 可在轉換目標後提供同型別的復原值。或取 是 nullable elimination,不是邏輯 OR。

呼叫與成員存取#

call          := primary (callSuffix | memberSuffix | optionalSuffix | nonNullSuffix)*
callSuffix    := typeArgs? '(' argumentList ')'
memberSuffix  := '.' IDENTIFIER | '[' expression ']'
optionalSuffix := '?.' IDENTIFIER | '?[' expression ']' | '?(' argumentList ')'
nonNullSuffix := '!.' IDENTIFIER | '![' expression ']' | '!(' argumentList ')'
argumentList  := (argument (',' argument)*)?
argument      := '展開'? expression

字串與範本字面值#

Faber 使用分隔符語意;每種引號形式都代表不同的來源形狀。

形式型別用途
'...'ascii固定機器 token
"..."文字短 Unicode 行字串
«...»文字區塊或多行 Unicode 字串
... forma擷取範本
{ ... }json編譯期 JSON 文件
\|...\|位元組編譯期十六進位位元組
"..." ↦ regexregex從文字轉換為編譯後模式
[ ... ]列表<T>Faber 列表

Unicode 字串範本中的 § 是洞。文字 的格式範本呼叫會產生 scriptumforma 會擷取文字與參數,不會立即渲染。

定值 _ 標籤 ← «inline»
定值 _ 查詢 ← `select * from accounts where id = §`(accountId)
定值 _ 簽章 ← |de ad be ef|
"status: § (§)"(sample_status(), "ok")
"hello world"[0‥5]

文字 而言,方括號索引以 Unicode scalar 為單位。文字切片接受完整 range 形式,包括

列表<T> 而言,方括號索引是單一元素存取;索引必須是單一整數,不接受 range slice(要複製範圍請使用 sectio(start, end))。列表方括號存取是一般存取,不是 nullable:回傳裸元素 T,越界時觸發陷阱。若需要 nullable 列表存取,使用 xs.accipe(i) → T ∪ 無 搭配 或取

tensor<T, Figura> 而言,方括號索引是 tensor intrinsic 表面的語法糖:

vector[id]        # vector.accipe([id])
vector[id] ← v    # vector.ponde([id], v)
grid[[r, c]]      # grid.accipe([r, c])
grid[[r, c]] ← v  # grid.ponde([r, c], v)

讀取回傳 T ∪ 無,與 accipe 一致;參與算術前請先使用 或取 或其他一般選項處理。rank-1 tensor 接受符合 tensor i64 執行期邊界的純量整數索引(拒絕 u64)。rank-N tensor 使用列表形狀的索引,例如 [[r, c]] 或繫結的 lista<integer> 值。grid[r, c] 不是語法;memberSuffix 的方括號內仍只有一個 expression

位元組 是位元組緩衝原語,不是陣列,因此不接受方括號索引(讀取或寫入)。位元組存取使用 accipeappendelongitudo 方法;accipe 越界時回傳 nullable 值。對高密度位元組索引,內部可使用 lista<numerus<u8>>,並在邊界保留 位元組

基本運算式#

primary := IDENTIFIER | NUMBER | STRING | ASCII_STRING | BACKTICK_STRING
         | '自身' | '真' | '假' | '無'
         | 'vacua' | arrayLiteral | jsonLiteral | typedConstructor
         | adExpr
         | '(' expression ')'
adExpr    := '對' asciiLiteral adOpener?
arrayLiteral := '[' argumentList? ']'
jsonLiteral := '{' (jsonMember (',' jsonMember)* ','?)? '}'
jsonMember  := STRING ':' jsonValue
typedConstructor := typeAnnotation '{' fieldList? '}'
fieldList := fieldInit (',' fieldInit)*
fieldInit := ('展開' expression) | (fieldKey '=' expression) | IDENTIFIER
fieldKey := IDENTIFIER | STRING | '[' expression ']'
jsonValue := jsonObject | jsonArray | jsonString | jsonNumber | 'true' | 'false' | 'null'
jsonObject := '{' (jsonMember (',' jsonMember)* ','?)? '}'
jsonArray  := '[' (jsonValue (',' jsonValue)* ','?)? ']'
jsonString := STRING
jsonNumber := NUMBER

{ ... } 是 JSON 文件。key 必須是帶引號的 JSON 字串,值只能是 JSON 常數。重複 key 會報錯。類型或變體建構使用 Type { field = value }= 的 Faber grammar 保持不變。

特殊運算式#

fingeExpr     := '虛構' IDENTIFIER ('{' fieldList '}')? ('∷' IDENTIFIER)?
praefixumExpr := '前綴' (blockStmt | '(' expression ')')
formatStringExpr := STRING '(' argumentList ')'
formaTemplateExpr := BACKTICK_STRING '(' argumentList ')'
scriptumExpr  := '格式文字' '(' STRING (',' expression)* ')'
legeExpr      := '讀取' '行'?
regexFromText := (STRING | ASCII_STRING) '↦' 'regex'

---

模式#

objectPattern  := '{' patternProperty (',' patternProperty)* '}'
patternProperty := '其餘'? IDENTIFIER ('作為' IDENTIFIER)?
arrayPattern   := '[' arrayPatternElement (',' arrayPatternElement)* ']'
arrayPatternElement := '_' | '其餘'? IDENTIFIER

---

診斷#

outputStmt := ('註記' | '檢視' | '警告' | '寫出') expression (',' expression)*

註記 是中性的診斷 note,檢視 用於 debug 或 inspect,警告 用於 warn,寫出 是診斷通道拼寫。真正的輸出請使用目前標準函式庫方法。

註解#

Faber 只接受行註解# 延伸至行尾。# 必須是邏輯行上的第一個非空白 token;只略過前導 ASCII 空格與 tab,其他 Unicode 空白分隔符不會由 lexer 略過。同一行若在其他 token 後出現 #,會產生詞法錯誤:# comments must start a line; move this comment above the code

合法的行首註解會以前置 trivia 附加到下一個陳述式或宣告(見 comment-preservation)。字串、ascii 字面值、forma 範本與其他分隔字面值內的 # 都不是註解。

---

入口點#

incipitStmt  := '入口' blockStmt
incipietStmt := '非同步入口' blockStmt

入口 是同步入口;非同步入口 是非同步入口。

---

測試#

probandumDecl := '測試規格' STRING probaModifier* '{' probandumBody '}'
probandumBody := (praeparaBlock | probandumDecl | probaStmt)*
probaStmt     := '測試' STRING probaModifier* blockStmt
probaModifier := '略過' STRING | '未來' STRING | '僅限' | '標籤' STRING
              | '時限' NUMBER | '測量' | '重複' NUMBER | '脆弱' NUMBER
              | '需要' STRING | '僅限於' STRING
praeparaBlock := ('準備' | '準備非同步' | '後置準備' | '後置準備非同步') '全部'? blockStmt

---

CLI 框架#

cliDecl       := annotation* (incipitStmt | funcDecl)
cliAnnotation := cliProgramAnnotation | imperiumAnnotation | optioAnnotation | operandusAnnotation

Faber 支援建立 CLI 應用程式,並自動解析引數與產生 help。

@ cli "faber"
@ optio verbose 長 "verbose" 型別 bivalens
入口 引數 args {
    # CLI 框架會自動解析引數
}
@ imperium "deploy"
@ optio target 短 "t" 長 "target" 型別 文字 說明 "部署目標"
@ optio verbose 短 "v" 長 "verbose" 型別 布林 說明 "啟用詳細輸出"
@ 位置引數 文字 file 說明 "要部署的檔案"
函式 deploy() 引數 args {
    # 引數會自動解析並傳入
}

---

能力呼叫#

expression-form 是唯一支援的 ad 表面。舊式具型別 ad 和區塊串流形式已在解析時拒絕。

adExpr        := '對' asciiLiteral adOpener?
adOpener      := '(' expression ')'
conversioExpr := expr '↦' typeAnnotation
  • route 必須是 asciiLiteral,例如 'solum:lege',不能使用雙引號 STRING
  • opener 是可選的單一 expression,會作為 Request datavalor
  • 運算式形式的 `對` 不帶區塊;求值結果是 sermo 對話 handle。可使用 postfix ↦ T 物化、指定給 sermo,或開啟即時方向 view:s.meus<T>()(輸出 dafini)與 s.tuus<T>()(輸入 accipecursorexhaurifini)。輸入內容 frame 請使用 s.tuus<T>().cursor() 迭代,不要直接寫 遍歷 取自 s.tuus<T>()
  • 已移除且會產生解析錯誤的表面:舊式具型別 對 "route"、區塊 meustuus 分支,以及陳述式層級的 發出
  • 型別包括編譯器擁有的 scriniumstatus,以及不透明的 sermo 對話 handle。
  • sermo ↦ T 會使用針對 T 的型別導向 collector,把輸入 frame 物化為單一 T 值。

詳見 docs/design/frame-stream-types.md

---

集合操作#

舊的 ab 集合 pipeline DSL 已淘汰。篩選、切片與聚合應使用 文字列表表格副本 方法與閉包。primaultima 是普通方法名稱;ubi 不是有效集合語法。取自 用於迭代與匯入。

---

Fac 區塊#

facBlockStmt := '執行' blockStmt catchClause? ('當' expression)?

執行 { ... } 執行一次作用域區塊。執行 { ... } 捕捉 err { ... } 是區域復原錯誤邊界。執行 { ... } 當 condition 是 post-test loop;postfix 只附加到 執行

---

目標支援#

目標支援不是文法的一部分。本文只定義語言;各編譯目標可降低的文法與 runtime policy 請參考 EBNF_MATRIX.md 與 target capability 文件。

---

關鍵字參考#

文法中的關鍵字按宣告、控制流程、錯誤處理、非同步、端點、布林、物件、型別形狀、型別轉換、位元運算與診斷分類。 等 glyph 永遠不翻譯,也不應在 reader pack 中建立 glyph 別名。

分類讀者表面說明
宣告分支聯集定值函式類型介面型別宣告資料、函式、型別與契約
控制流程 / 否則若 / 否則遍歷選擇 / 分支比對條件、迴圈、分派與模式比對
錯誤處理捕捉斷言拋出崩潰執行區域錯誤邊界與控制轉移
非同步@ 未來@ 游標讓出非同步函式、產生器與上下文等待/讓出
端點發出 是能力呼叫運算式;發出 已退役
布林或取布林、比較與區域 nullable 消除
物件自身虛構self 與 variant 建構
形狀/轉換靜態標註、執行期轉換與復原值
位元¬位元 AND、OR、XOR、NOT 與移位
診斷註記檢視警告寫出診斷通道,不等同於一般輸出

---

關鍵語法規則#

  1. 參數採型別優先:函式 f(整數 n),不是名稱後置型別。
  2. 宣告採型別優先:定值 文字 name,不是 name: 文字
  3. 迭代語句使用 遍歷 取自/從 collection 定值/變值 item { }遍歷 自 range 定值/變值 item { }
  4. 條件可加括號,但慣用形式是不加括號。
  5. 診斷關鍵字是語句,不是可呼叫值。

Reader pack glossary (machine extract)#

Keywords#

LatinLocalized
discretio分支聯集
fixum定值
functio函式
genus類型
implendum待實作介面
importa匯入
modulus模數
ordo列舉
sit設為
typus型別
varia變值
abstractus抽象
ceteri其餘
curata管理
errata錯誤
exitus出口
generis靜態
iacit可拋
immutata不變
magnitudo尺寸
nexum綁定
optiones選項
prae前置
privata私有
protecta保護
publica公開
sponte可選
casu分支
ceterum預設
custodi守衛
discerne比對
dum
elige選擇
ergo
fac執行
itera遍歷
secus否則
si
sic如此
sin否則若
perge繼續
redde傳回
rumpe中斷
tacet靜默
adfirma斷言
cape捕捉
cede讓出
iace拋出
mori崩潰
clausura閉包
falsum
nihil
verum
aut
est
et
non
vel或取
ego自身
finge虛構
implet實作
sub
mone警告
nota註記
scribe寫出
vide檢視
argumenta引數
cura資源
incipiet非同步入口
incipit入口
ad端點
de
ex取自
in傳入
lege讀取
lineam
omnia全部
praefixum前綴
scriptum格式文字
sparge展開
ut作為
ante之前
inter之間
intra內含
per
usque直到
fragilis脆弱
futurum未來
metior測量
omitte略過
postpara後置準備
postparabit後置準備非同步
praepara準備
praeparabit準備非同步
proba測試
probandum測試規格
repete重複
requirit需要
solum僅限
solum_in僅限於
tag標籤
temporis時限
negativum
nonnihil非空
nonnulla若干
nulla可空
positivum

Types#

LatinLocalized
asciiascii
textus文字
numerus整數
modulus模數
fractus小數
bivalens布林
nihil
vacuum空值
numquam永不
ignotum未知
octeti位元組
regex正規表示式
jsonJSON
valor
instans執行個體
objectum物件
quidlibet任意值
lista列表
tabula表格
copia副本
promissum承諾
cursor游標

Glossary changes vs existing pack#

LatinOld packNew (this EBNF)Why
functio函式函式保留既有繁體用語。
fixum常數定值與不可變 binding 的語意一致,避免與數學常數混淆。
sin否則如果否則若臺灣技術文件較自然,且保持單一 token。
secus否則否則保留既有用語。
redde傳回傳回保留既有用語。
nota顯示註記與診斷 note 的語意一致,不與一般輸出混淆。
textus文字文字保留既有用語。
numerus整數整數保留既有用語。