通过 IR 进行解释而不将所有内容都表示为枚举?

Edw*_*ers 6 rust

我正在尝试编写一个简单的 IR 解释器。我知道如何使用 IR 和返回类型的枚举来执行此操作,但有几个原因我不想这样做:

  • 我有几个部分重叠的 AST,并且希望避免每个 AST 的冗余代码。(例如,Data 和 IR 共享许多非常相似的节点,如果能够输入 IR 以便某些节点仅在特定上下文中有效,那就太好了)
  • 我希望能够进行更强大的类型推断 和impl,当 an 中的所有内容都enum属于同一类型时,这会受到限制
  • 我正在探索多种选择,并希望确保我已经涵盖了我的基础

因此,我非常希望摆脱由特征表示的 IR 和返回数据,例如:

trait Data{}
trait IR{
    fn evaluate(self) -> Box<dyn Data>;
}
Run Code Online (Sandbox Code Playgroud)

但我在尝试进行评估时遇到了障碍:

struct Bool(bool);
impl Data for Bool{}
//other things impl Data, of course

struct IfThenElse<T1, T2, T3>{
    condition: T1,
    then_branch: T2,
    else_branch: T3
}
impl<T1, T2, T3> IR for IfThenElse<T1, T2, T3> where T1: IR, T2: IR, T3: IR{
    fn evaluate(self) -> Box<dyn Data>{
        let condition_evaluated = self.condition.evaluate();
        todo!(); //Uh oh: That's a Box<dyn Data>. It's reasonable to fail if it isn't a Bool, but how do I check that?
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,我需要能够使用返回类型执行特定的操作。在多种情况下,这是必要的 - IR 包括模式匹配、记录字段访问和函数应用,如果无法检查子节点的计算返回类型,所有这些都可能有条件地失败。

我可以想出很多解决这个问题的方法,但每种方法都遇到了不同的实现障碍,或者至少是混乱的:

  • Any和沮丧
  • 拥有enum包含每个特征的所有变体,以及来自和到特征实现结构的函数
  • 在特征上添加一堆函数Data以返回特定的具体类型
  • 一个大枚举,带有可以用于!某些类型的类型参数,有效地将它们从这些类型中排除
  • 毕竟放弃并只拥有大量枚举

我可以针对每个问题提出单独的问题,但我认为我更有可能错过了一种更基本和标准的方法。我试图找到 Rust 解释器的示例来寻找标准,但我发现的大部分内容要么是关于解析/词法分析,要么是针对比我需要的更复杂和性能优化的解决方案(尤其是第一次通过)。

特质模型有没有一种优雅的方法来解决这个问题?如果不是,我应该如何表示数据和 IR?

Aur*_*ílý 0

特质的价值是什么Data?你期望它有任何方法,还是纯粹是一个标记特征?

如果IR实际上是“可以评估为数据的东西”,这听起来很像“数据”是特征的关联类型:

trait IR {
    type Output;
    fn evaluate(self) -> Self::Output;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以限制IfThenElse实现,要求条件实际上计算为布尔值(并且两个分支具有相同的输出类型):

impl<T1, T2, T3> IR for IfThenElse<T1, T2, T3>
where
    T1: IR<Output = bool>,
    T2: IR,
    T3: IR<Output = T2::Output>,
{
    type Output = T2::Output;
    fn evaluate(self) -> Self::Output {
        if self.condition.evaluate() {
            self.then_branch.evaluate()
        } else {
            self.else_branch.evaluate()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它还避免了Boxed 特征对象,这似乎是不必要的。

如果您发现仍然需要一个必须由任何DataIR 评估的输出实现的特征,那么您可以将其添加为关联类型的特征绑定。

trait IR {
    type Output: Data;
    // ...
}
Run Code Online (Sandbox Code Playgroud)