關於本指南
本文檔是開發Erg項目的指南 它描述了如何做出貢獻,做開發的指南,以及如何建立開發環境等
分支機構命名和運營策略
main(基於主幹的開發)
-
主要開發分支
-
必須滿足以下條件
-
編譯成功
beta(目前不創建)
-
最新的 Beta 版本
-
必須滿足以下條件
-
編譯成功
-
所有測試都會成功
feature-*(名字)
-
開發特定功能的分支
-
切開 main
-
沒有條件
issue-*(#issue)
-
解決特定 issue 的分支
-
沒有條件
fix-*(#issue or bug 名字)
-
修復特定錯誤的分支(如果該問題是一個錯誤,則代替
issue-*
創建) -
沒有條件。
erg
構建功能
debug
進入調試模式。結果,Erg 內部的行為順序顯示在日誌中
獨立於 Rust 的 debug_assertions
標誌
japanese
將系統語言設置為日語 Erg 內部選項、幫助(幫助、版權、許可證等)和錯誤顯示為日語
simplified_chinese
將系統語言設置為簡體中文 Erg 內部選項、幫助(幫助、版權、許可證等)和錯誤顯示為簡體中文
traditional_chinese
將系統語言設置為繁體中文 Erg 內部選項、幫助(幫助、版權、許可證等)和錯誤顯示為繁體中文。
unicode/pretty
使得編譯器顯示豐富內容
pre-commit
用於在預提交中運行測試。這是一個bug解決方案
large_thread
增加線程堆棧大小。用於Windows執行和測試執行
els
通過 --language-server
使其變得可用
通過 erg --language-server
打開
py_compatible
啟用Python兼容模式,使部分api和語法與Python兼容。用於pylyzer
Erg存儲表結構
└─┬ assets: 圖片等
├─ CODE_OF_CONDUCT: 行為準則
├─┬ crates
│ ├─ els: Erg語言服務器 (Language Server)
│ ├─ erg_common: 通用工具
│ ├─ erg_compiler: 編譯器,**Erg核心**
│ └─ erg_parser: 解析器
├─┬ doc: 文檔
│ ├─┬ CN
│ │ ├─ API: Erg標準API
│ │ ├─ compiler: 關于編譯器實現
│ │ ├─ dev_guide: 開發者和貢獻者指南
│ │ ├─ python: Erg開發必備的Python知識
│ │ ├─ syntax: Erg語法
│ │ └─ tools: Erg命令行工具
│ └─┬ JA
│ ...
├─ examples: 示例代碼
├─ library: Erg腳本庫
├─ src: main.rs和驅動所在目錄
└─ tests: 測試代碼
格式
任何不符合以下規則的文件都將得到更正
- 以某種語氣寫代碼注釋或內部文檔
- 向外部(普通用戶)展示的文檔應該越來越多地編寫
- 始終包含定義、含義或文檔中首次出現的術語的鏈接
- 僅對理解正文所必需的補充句子使用括號作為附加條件,對于理解正文不是必需的句子使用腳注1</ sup>
- 如果文檔內容過時,按照此方法更新
1 參見這里了解如何編寫腳注。↩
在應用程序中嵌入Erg編譯器
在應用程序中嵌入Erg很容易
[dependencies]
erg = "0.5.12" # 選擇最新版本
use erg::DummyVM; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut vm = DummyVM::default(); let _res: String = vm.eval("print! \"Hello, world!\"")?; Ok(()) }
執行需要Python
還有一個不連接到運行時的獨立編譯器版本
[dependencies]
erg_compiler = "0.5.12" # 選擇最新版本
use erg_compiler::Compiler; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut compiler = Compiler::default(); let code = compiler.compile("print!\"Hello, world!\"", "exec")?; code.dump_as_pyc("o.pyc", None)?; Ok(()) }
Compiler
輸出一個名為CodeObj
的結構。這通常不是很有用,所以你可能想要使用Transpiler
,它輸出一個Python腳本
use erg_compiler::Transpiler; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut transpiler = Transpiler::default(); let script = transpiler.transpile("print!\"Hello, world!\"", "exec")?; println!("{}", script.code); Ok(()) }
其他示例還有輸出HIR(高級中間表示)的HIRBuilder
和輸出AST(抽象語法樹)的ASTBuilder
use erg_compiler::HIRBuilder; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut builder = HIRBuilder::default(); let artifact = builder.build("print!\"Hello, world!\"", "exec")?; println!("{}", artifact.hir); Ok(()) }
use erg_compiler::ASTBuilder; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut builder = ASTBuilder::default(); let ast = builder.build("print! \"Hello, world!\")")?; println!("{}", ast); Ok(()) }
執行語義分析的結構實現了一個名為ContextProvider
的trait。它可以獲取模塊中變量的信息,等等
use erg_compiler::Transpiler; use erg_compiler::context::ContextProvider; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut transpiler = Transpiler::default(); let script = transpiler.transpile("i = 0", "exec")?; println!("{}", script.code); let typ = transpiler.get_var_info("i").0.t; println!("{typ}"); Ok(()) }
開發環境
你需要安裝什麽
-
Rust(與 rustup 一起安裝)
- 版本 >= 1.64.0
- 2021年版
我們使用pre-commit來自動進行clippy檢查和測試。即使沒有錯誤,檢查也可能在第一次運行時失敗,在這種情況下,您應該再次嘗試提交。
- Python3 解釋器
推薦
- 編輯器: Visual Studio Code
- VSCode 擴展: Rust-analyzer、GitLens、Git Graph、GitHub Pull Requests and Issues、Markdown All in One、markdownlint
- 操作系統: Windows 10/11 | Ubuntu 20.04/22.04 | macOS Monterey/Ventura
多語言錯誤信息
Erg 正在推動消息(開始、選項、文檔、提示、警告、錯誤消息等)的多語言化。如果你不熟悉 Rust 或 Erg,也可以參與此項目。請務必配合
以下是多語種方法的說明
查找switch_lang!
在 Erg 源代碼中找到(使用 grep 或編輯器的搜索功能)。我們應該能找到下面這樣的東西
#![allow(unused)] fn main() { switch_lang!( "japanese" => format!("この機能({name})はまだ正式に提供されていません"), "english" => format!("this feature({name}) is not implemented yet"), ), }
此消息目前僅支持日語和英語。讓我們嘗試添加簡體消息
添加消息
請在查看其他語言內容的同時添加翻譯消息。最后不要忘記逗號(,)
#![allow(unused)] fn main() { switch_lang!( "japanese" => format!("この機能({name})はまだ正式に提供されていません"), "simplified_chinese" => format!("該功能({name})還沒有正式提供"), "english" => format!("this feature({name}) is not implemented yet"), ), }
另外,英語是默認設置,一定要排在最后
{name}
部分是 Rust 的格式化功能,允許你將變量的內容(name
)嵌入到字符串中
構建
現在,我們使用選項構建它
你做到了!
FAQ
Q: 像這樣的指定是什么意思?A: {RED} 及更高版本將顯示為紅色。重新啟動交互渲染
Q: 如果想添加自己的語言,該如何替換部分?答: 目前支持以下語言
- "english"(默認設置)
- "japanese" (日語)
- "simplified_chinese" (簡體中文)
- "traditional_chinese" (繁體中文)
如果你想添加其他語言,請提出請求。
Rust 代碼指南
本地規則
- 使用
log!
進行調試輸出(使用println!
等進行輸出處理,這也是發布所必需的) - 未使用或內部變量/方法(私有且僅用於特定功能)必須以
_
為前綴。如果要避免與保留字沖突,請在末尾添加一個_
- 使用clippy。然而,有些規則是不合理的,所以你可以使用
#[allow(clippy::…)]
來忽略除「deny」之外的規則。
推薦代碼
- 定義和使用特定領域的枚舉而不是數字枚舉或布爾值
- 將訪問修飾符保持在最低限度。即使在發布時也要優先使用
pub(mod)
或pub(crate)
- 將 for 表達式中的可迭代對象顯式轉換為迭代器(
for i in x.iter()
而不是for i in x
) - 懶惰的評價。例如,如果
default
不是文字,請使用unwrap_or_else
而不是unwrap_or
不鼓勵使用代碼
- 大量使用返回類型重載。特別是使用大量非顯而易見的
.into
的代碼。這是因為類型推斷結果可能違反直覺。在這種情況下,建議使用from
代替 - 大量使用
Deref
。這有效地提出了與繼承相同的問題
根據上下文做出決策的代碼
- 定義未使用的輔助方法
- 大量使用
unwrap
和clone
。在某些情況下,沒有什麽比這樣做更好的了。
依賴關系
依賴關系應該盡可能地最小化,那些必要的依賴關系應該由Erg開發團隊來實現。只有當外部依賴很難實現或依賴於硬件時才允許使用。例如:libc
, winapi
),或者沒有外部依賴的crate(例如:unicode-xid
)。否則,它們可能被允許作為可選依賴項(例如https客戶端)。在任何情況下,都應選擇保養良好和廣泛使用的
此規則僅適用於Erg編譯器, Erg工具和庫可以自由添加它們自己的依賴項。
測試
測試是確保代碼質量的重要部分
使用以下命令執行測試
cargo test --features large_thread
由于cargo需要一個小線程來運行測試,我們使用 large_thread
標志來避免堆棧溢出
放置測試
根據實現的特性來安排它們。將解析器測試放置在erg_parser/tests
下,將編譯器(類型檢查器等)測試放置在erg_compiler/tests
下,將用戶可以直接使用的語言特性測試放置在erg/tests
下(然而,這些測試目前正在開發中,不一定按照這種慣例安排)
如何編寫測試
有兩種類型的測試。positive測試和negative測試。 positive測試是檢查編譯器是否按預期運行的測試,而negative測試是檢查編譯器是否正確地輸出無效輸入的錯誤。 由于編程語言處理器的性質,在所有軟件中,它們特別容易受到無效輸入的影響,并且必須始終將錯誤呈現給用戶,因此后者也必須得到照顧。
如果你在語言中添加了一個新特性,你至少需要寫一個positive測試。另外,如果可能的話,請寫同時編寫negative測試。
故障診斷
Q: 本地生成成功, 但 GitHub Actions 生成失敗
A: 您正在處理的分支可能沒有Pullmain
中的更改
Q: 提交前檢查失敗
A: 嘗試再次提交, 第一次可能會誤判, 如果一次又一次的失敗, 那么你的代碼可能包含錯誤
Q: build.rs 無法正常運行
A: 檢查 build.rs
運行目錄中的額外文件/文件夾 (例如 __pychache__
)
版本控製
Erg 編譯器根據語義版本控製分配版本號。 但是,在版本 0 期間,應用的規則與平時不同(遵循比語義版本控製更詳細的規則)。 需要註意的是,Erg 中有兩種類型的兼容性。一個是規範兼容性,表示與語言規範的兼容性,另一個是內部兼容性,表示與(公共)API(如編譯器)的兼容性。
- 在版本 0 期間,次要版本中的規範和內部兼容性可能會中斷。這與正常的語義版本控製相同。
- 補丁版本不會破壞規範兼容性,但不能保證內部兼容性。
- 新功能主要在次要版本中添加,但如果它們是簡單的語言功能或編譯器功能,也可以在補丁版本中添加。
發布周期
- 補丁大約每 1~2 周發布一次。
- 次要版本的發布頻率大約是補丁發布的 10 倍,即每 3~6 個月發布一次。
- 主要版本是無限期發布的。目前未計劃版本 1 版本的計劃。
每晚/測試版
Erg 將不定期進行夜間和測試版發布。每晚發布是新補丁版本的預發布,測試版是新的次要/主要版本的預發布。 每晚和測試版發布在 crates.io 上,測試版也發布在 GitHub 版本上。
每晚版本的格式是0.x.y-nightly.z
。測試版也是如此。
幾乎每天都會發布每晚版本(如果沒有更改,則不會發布),而測試版則不定期發布。但是,一旦發布測試版,幾乎每天都會發布新的測試版。