【发布时间】:2016-09-28 02:47:33
【问题描述】:
作为学习 Racket 宏系统的练习,我一直在实现一个基于 C++ catch framework 的单元测试框架。该框架的一个特点是,如果我写这样的检查:
CHECK(x == y); // (check x y)
当检查被违反时,错误消息将打印出 x 和 y 的值,即使使用的宏是完全通用的,不像其他需要您使用宏(如 CHECK_EQUALS、CHECK_GREATER 等)的测试框架。这是可能的通过一些涉及表达式模板和运算符重载的hacky。
在我看来,在 Racket 中你应该能够做得更好。在 C++ 版本中,宏看不到子表达式内部,所以如果你写这样的东西:
CHECK(f(x, g(y)) == z); // (check (= (f x (g y)) z))
当检查被违反时,您只能找到等号左右两侧的值,而不是 x、y 或 g(y) 的值。在球拍中,我希望可以递归到子表达式并打印一棵树来显示评估的每个步骤。
问题是我不知道最好的方法是什么:
- 我已经相当熟悉语法分析,但这似乎超出了它的能力。
- 我读到了关于自定义 #%app 的文章,这几乎是我想要的,但是如果例如 f 是一个宏,我不想打印扩展中表达式的每个评估,只打印用户调用 check 宏时可见的表达式。也不确定我是否可以在不定义语言的情况下使用它。
- 我可以使用 syntax-parameterize 来劫持基本运算符的含义,但这对 g(y) 之类的函数调用没有帮助。
- 我可以使用 syntax->datum 并手动遍历 AST,我自己在子表达式上调用 eval。这似乎很棘手。
- 跟踪库几乎看起来就像我想要的那样,但你必须预先给它一个函数列表,而且它似乎不能让你控制输出的去向(我只想打印如果检查失败,而不是成功,则没有任何结果,因此我需要在执行过程中将中间值保存到一边)。
什么是最好的或至少是惯用的实现方式?
【问题讨论】:
-
投票结束的人会解释原因吗?这个问题非常具体,我不确定如何将其解释为“广泛”
标签: macros scheme racket evaluation expression-evaluation