关于本指南
本文档是开发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
。测试版也是如此。
几乎每天都会发布每晚版本(如果没有更改,则不会发布),而测试版则不定期发布。但是,一旦发布测试版,几乎每天都会发布新的测试版。