#codegen #mixing #autogenerated #hand-written

codebiber

混合手写代码和自动生成代码的库

2 个版本

0.0.1 2024年2月10日
0.0.0 2023年12月8日

#4 in #hand-written

Apache-2.0

34KB
695

Codebiber

此包是一个用于元编程的 Rust 库。它允许将自动生成的代码混合到手写代码中。它深受 Ned Batchelder 的 cog 应用程序的启发。

免责声明

此作品按“原样”提供,不提供任何类型的保证或条件。

这是一个实验性库,具有实验性的 API、行为和实现,没有长期计划。自行承担风险。

变更日志

v0.0.1

  • 最低支持的 Rust 版本是现在 1.63(对于常规构建,而不是开发构建) 05ed194ddaa2127b671c0345cfdf8e4330419242
  • 不再使用不稳定的功能 0341b2d033173a4f7d6e084ae14bd36f623db9d5

lib.rs:

示例

使用 codebiber 混合自动生成代码和手写代码的愚蠢示例。

在这里,原始代码包含手写行

void handwritten_line1();
void handwritten_line2();
void handwritten_line3();
void handwritten_line4();
void handwritten_line5();

和一些标记为要覆盖的部分

// << codegen foo >>
// << /codegen >>
// << codegen bar >>
// << /codegen >>

以及另一个函数已生成的部分

// << codegen baz >>
void generated_line_by_some_other_function();
// << /codegen >>

函数 generate 接受输入代码、一个 配置,最重要的是要生成的函数。

在我们的例子中,该函数将对每个部分调用一次。每次它接受部分名称(在我们的情况下 foobarbaz)并返回此部分的生成代码。如果部分不是其责任范围,它也可以返回 Ok(None) 并再次使用先前的内容。

在我们的例子中,生成函数 gen_code_linesfoobar 部分返回新的代码,而将 baz 保持不变。

这导致生成的代码部分

// << codegen foo >>
void autogen_line_foo();
// << /codegen aaa272 >>
// << codegen bar >>
void autogen_line_bar1();
void autogen_line_bar2();
// << /codegen 00a214 >>
// << codegen baz >>
void generated_line_by_some_other_function();
// << /codegen 810c07 >>

注意哈希值。它们可以防止意外修改的覆盖。它们只是 blake3 哈希的前几个字节(可以配置多少)。

extern crate codebiber;

const INPUT : &str = r"
void handwritten_line1();
void handwritten_line2();

// << codegen foo >>
// << /codegen >>

void handwritten_line3();

// << codegen bar >>
// << /codegen >>

void handwritten_line4();

// << codegen baz >>
void generated_line_by_some_other_function();
// << /codegen >>

void handwritten_line5();
";

fn main() -> codebiber::Result
{
let cfg = codebiber::Config{
// Anything checksum length other than 0 will catch unintended modifications
// since the last modification.
checksum_bytes_to_store: 3,
};

let actual_output = codebiber::generate(INPUT, cfg, gen_code_lines)?;

assert_eq!(actual_output, Some(EXPECTED_OUTPUT.to_owned()));

Ok(())
}

fn gen_code_lines(name: &str) -> codebiber::Fmt_Result
{
let generated = match name
{
"foo" => Some("void autogen_line_foo();".to_owned()),
"bar" => Some("void autogen_line_bar1();\nvoid autogen_line_bar2();".to_owned()),
_ => None,
};
Ok(generated)
}

const EXPECTED_OUTPUT : &str = r"
void handwritten_line1();
void handwritten_line2();

// << codegen foo >>
void autogen_line_foo();
// << /codegen aaa272 >>

void handwritten_line3();

// << codegen bar >>
void autogen_line_bar1();
void autogen_line_bar2();
// << /codegen 00a214 >>

void handwritten_line4();

// << codegen baz >>
void generated_line_by_some_other_function();
// << /codegen 810c07 >>

void handwritten_line5();
";

请注意,bar 部分中生成的代码缩进。这是因为生成的代码继承了标记行的缩进 // << codegen bar >>

示例 2

虽然在这个例子中所有标记行都从 // 开始,但标记行可以以任何字符开始,只要它们不以 < 结尾,并且不包含 <<

extern crate codebiber;

const INPUT : &str = r"
/* << codegen foo >> 

依赖关系

~4.5MB
~99K SLoC