關於本指南

本文檔是開發Erg項目的指南 它描述了如何做出貢獻,做開發的指南,以及如何建立開發環境等

分支機構命名和運營策略

badge

main(基於主幹的開發)

  • 主要開發分支

  • 必須滿足以下條件

  • 編譯成功

beta(目前不創建)

  • 最新的 Beta 版本

  • 必須滿足以下條件

  • 編譯成功

  • 所有測試都會成功

feature-*(名字)

  • 開發特定功能的分支

  • 切開 main

  • 沒有條件

issue-*(#issue)

  • 解決特定 issue 的分支

  • 沒有條件

fix-*(#issue or bug 名字)

  • 修復特定錯誤的分支(如果該問題是一個錯誤,則代替issue-*創建)

  • 沒有條件。

erg 構建功能

badge

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存儲表結構

badge

  └─┬ 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: 測試代碼

格式

badge

任何不符合以下規則的文件都將得到更正

  • 以某種語氣寫代碼注釋或內部文檔
  • 向外部(普通用戶)展示的文檔應該越來越多地編寫
  • 始終包含定義、含義或文檔中首次出現的術語的鏈接
  • 僅對理解正文所必需的補充句子使用括號作為附加條件,對于理解正文不是必需的句子使用腳注1</ sup>
  • 如果文檔內容過時,按照此方法更新

1 參見這里了解如何編寫腳注。

在應用程序中嵌入Erg編譯器

badge

在應用程序中嵌入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(())
}

開發環境

badge

你需要安裝什麽

  • Rust(與 rustup 一起安裝)

    • 版本 >= 1.64.0
    • 2021年版
  • pre-commit

我們使用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

多語言錯誤信息

badge

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)嵌入到字符串中

構建

現在,我們使用選項構建它

screenshot_i18n_messages

你做到了!

FAQ

Q: 像這樣的指定是什么意思?A: {RED} 及更高版本將顯示為紅色。重新啟動交互渲染

Q: 如果想添加自己的語言,該如何替換部分?答: 目前支持以下語言

  • "english"(默認設置)
  • "japanese" (日語)
  • "simplified_chinese" (簡體中文)
  • "traditional_chinese" (繁體中文)

如果你想添加其他語言,請提出請求。

Rust 代碼指南

badge

本地規則

  • 使用 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。這有效地提出了與繼承相同的問題

根據上下文做出決策的代碼

  • 定義未使用的輔助方法
  • 大量使用 unwrapclone。在某些情況下,沒有什麽比這樣做更好的了。

依賴關系

依賴關系應該盡可能地最小化,那些必要的依賴關系應該由Erg開發團隊來實現。只有當外部依賴很難實現或依賴於硬件時才允許使用。例如:libcwinapi),或者沒有外部依賴的crate(例如:unicode-xid)。否則,它們可能被允許作為可選依賴項(例如https客戶端)。在任何情況下,都應選擇保養良好和廣泛使用的

此規則僅適用於Erg編譯器, Erg工具和庫可以自由添加它們自己的依賴項。

測試

badge

測試是確保代碼質量的重要部分

使用以下命令執行測試

cargo test --features large_thread

由于cargo需要一個小線程來運行測試,我們使用 large_thread 標志來避免堆棧溢出

放置測試

根據實現的特性來安排它們。將解析器測試放置在erg_parser/tests下,將編譯器(類型檢查器等)測試放置在erg_compiler/tests下,將用戶可以直接使用的語言特性測試放置在erg/tests下(然而,這些測試目前正在開發中,不一定按照這種慣例安排)

如何編寫測試

有兩種類型的測試。positive測試和negative測試。 positive測試是檢查編譯器是否按預期運行的測試,而negative測試是檢查編譯器是否正確地輸出無效輸入的錯誤。 由于編程語言處理器的性質,在所有軟件中,它們特別容易受到無效輸入的影響,并且必須始終將錯誤呈現給用戶,因此后者也必須得到照顧。

如果你在語言中添加了一個新特性,你至少需要寫一個positive測試。另外,如果可能的話,請寫同時編寫negative測試。

故障診斷

badge

Q: 本地生成成功, 但 GitHub Actions 生成失敗

A: 您正在處理的分支可能沒有Pullmain中的更改

Q: 提交前檢查失敗

A: 嘗試再次提交, 第一次可能會誤判, 如果一次又一次的失敗, 那么你的代碼可能包含錯誤

Q: build.rs 無法正常運行

A: 檢查 build.rs 運行目錄中的額外文件/文件夾 (例如 __pychache__)

版本控製

badge

Erg 編譯器根據語義版本控製分配版本號。 但是,在版本 0 期間,應用的規則與平時不同(遵循比語義版本控製更詳細的規則)。 需要註意的是,Erg 中有兩種類型的兼容性。一個是規範兼容性,表示與語言規範的兼容性,另一個是內部兼容性,表示與(公共)API(如編譯器)的兼容性。

  • 在版本 0 期間,次要版本中的規範和內部兼容性可能會中斷。這與正常的語義版本控製相同。
  • 補丁版本不會破壞規範兼容性,但不能保證內部兼容性。
  • 新功能主要在次要版本中添加,但如果它們是簡單的語言功能或編譯器功能,也可以在補丁版本中添加。

發布周期

  • 補丁大約每 1~2 周發布一次。
  • 次要版本的發布頻率大約是補丁發布的 10 倍,即每 3~6 個月發布一次。
  • 主要版本是無限期發布的。目前未計劃版本 1 版本的計劃。

每晚/測試版

Erg 將不定期進行夜間和測試版發布。每晚發布是新補丁版本的預發布,測試版是新的次要/主要版本的預發布。 每晚和測試版發布在 crates.io 上,測試版也發布在 GitHub 版本上。

每晚版本的格式是0.x.y-nightly.z。測試版也是如此。

幾乎每天都會發布每晚版本(如果沒有更改,則不會發布),而測試版則不定期發布。但是,一旦發布測試版,幾乎每天都會發布新的測試版。