4

我想编写一个简单的 Ruby DSL 来将一些语句和表达式翻译成另一种语言。一个基本的例子是:

some_function {
    t + 2
}

在这里, t 不是 ruby​​ 变量,因此块不能(也不能!)由 Ruby 评估。所以我最好的选择是使用解析输出(或 AST)自己进行翻译。为此,我可以使用 ParseTree 和 ruby​​2ruby。但是,我还有其他想要使用的构造,例如:

1.upto(10) {|x|
    some_function {
        t + x
    }
}

在这里,我有一个局部变量,我需要获取它的值才能进行翻译。但是,在执行块评估的函数中,我无权访问调用块的局部变量。如果它是一个全局变量 ($x),我可以检查它的名称是否存在于 global_variables 数组中,并且在最坏的情况下使用 eval,但是如果可能的话,我怎么能对局部变量这样做呢?

更新:

只是为了收拾东西。就像我最初说的那样,我使用 ruby​​2ruby(以及因此 ParseTree)来获取与块对应的 AST(使用 to_sexp)。但是在我的块中使用局部变量时,我遇到以下情况:

[:dvar, :x]

因此,我需要从变量的名称中获取变量的值作为字符串/符号。而且我不能使用 method_missing 或 instance_eval,因为我想将整个表达式翻译成另一种语言或语法(如 RPN)。

尽管如此,另一种不基于 ParseTree 的解决方案仍将受到欢迎,因为 Ruby 1.9 显然不完全支持它。

4

3 回答 3

1

要获取变量值,请使用 proc 的绑定:

def some_function(&block)
  b = block.binding
  p [b.eval("t"), b.eval("x")]
end

t = 1
1.upto(10) {|x|
  some_function {
    t + x
  }
}
于 2009-05-09T16:05:28.967 回答
0

在这里, t 不是 ruby​​ 变量,因此块不能(也不能!)由 Ruby 评估。

“未评估”限制的任何原因?似乎method_missing可以优雅地处理评估“缺失”t变量,但 Ruby 会自动取消引用该x变量。

于 2009-05-09T12:13:38.227 回答
0

您可以对带有t.

class Context
  attr_accessor :t

  def initialize(_t)
    @t = _t
  end
end

def some_function(&block)
  puts Context.new(1).instance_eval(&block)
end

1.upto(10) {|x|
  some_function {
    t + x
  }
}
于 2009-05-09T12:24:07.900 回答