编写可编译阶段的可维护测试

时间:2018-02-04 19:20:56

标签: unit-testing testing compiler-construction rust

这个问题可能会有点模糊,所以请提前道歉。简而言之:您如何为不易破解的编译器阶段编写测试。

我正在研究的编译器包含四个阶段,其中(大部分)定义明确的输入和输出,因此:

源代码 - > lex() - > 令牌 - > parse() - > AST - > intermediate() - > IR - > generation() - >的输出

每个阶段的现有测试只是将输出与预期结果进行比较,例如:

assert_eq!(
    lex("section { things }"),
    vec![Section, LeftBrace, Ident("things"), RightBrace]
);

该项目是用Rust编写的,但问题比这更普遍。

然而,由于输入和输出更复杂,因此在后期阶段会更加冗长:

assert_eq!(
    intermediate(Ast { root: SectionNode { attr: vec![AttributeNode { ... }] } }),
    SectionModel { things: vec![etc...] }
);

这意味着两件事:

  1. 添加新测试需要大量输入/复制粘贴。
  2. 几乎任何结构的更改都需要更新每个测试。
  3. 我目前正在通过使用源代码作为测试的输入,并在测试中对其进行解析并将其解析而将其放在一边,但这意味着词法分析器中的任何错误都会导致字面上的每个测试失败,这是......不理想。

    我觉得必须有一种更好的方法来测试本质上具有复杂输入/输出结构的函数,但我并不完全确定它是什么。

1 个答案:

答案 0 :(得分:0)

LLVM是可测试编译器的一个很好的例子。它在很大程度上被组织为通行证的集合。 llc可以通过 -stop-after 从其中一台机器发出MIR(一种中间语言)。可以使用 -simplify-mir 清除MIR,以生成可编辑的输出。也可以从捕获的中间表格开始运行过程,从而简化测试用例的调试。考虑到这种可测性方法,从整体DAGISel重新构造了面向更通行的GlobalISel指令选择框架。