Mis*_*don 5 compiler-construction testing unit-testing rust
这个问题最终可能有点含糊,所以提前道歉。简而言之:如何为不易中断的编译器阶段编写测试。
我正在使用的编译器由四个阶段组成,其中(大部分)具有明确定义的输入和输出,因此:
源代码-> lex() ->标记-> parse() -> AST -> middle() -> IR -> generation() ->输出
每个阶段的现有测试只是将输出与预期结果进行比较,例如:
assert_eq!(
lex("section { things }"),
vec![Section, LeftBrace, Ident("things"), RightBrace]
);
Run Code Online (Sandbox Code Playgroud)
该项目是用 Rust 编写的,但问题比这更普遍。
然而,随着输入和输出更复杂,这在后面的阶段变得更加冗长:
assert_eq!(
intermediate(Ast { root: SectionNode { attr: vec![AttributeNode { ... }] } }),
SectionModel { things: vec![etc...] }
);
Run Code Online (Sandbox Code Playgroud)
这意味着两件事:
我目前正在通过使用源代码作为测试的输入并在测试中对其进行词法分析和解析来在某些地方回避这一点,但这意味着词法分析器中的任何错误都会导致实际上每个测试都失败。 .. 不理想。
我觉得必须有更好的方法来测试本质上是具有复杂输入/输出结构的函数,但我不确定它是什么。
可测试编译器的一个很好的例子是 LLVM。它主要被组织为通行证的集合。llc 可以通过-stop-after从一台机器发出 MIR(中间语言之一)。可以使用-simplify-mir清理 MIR以生成人类可编辑的输出。还可以从捕获的中间形式开始运行一次传递,从而更轻松地调试测试用例。更面向传递的 GlobalISel 指令选择框架是根据单片 DAGISel 重新构建的,并考虑到了这种可测试性方法。