私は最近、パーサーとパーサー ジェネレーター、および DSL 設計におけるそれらの使用法をいじり始めました。物事を開始し、一石二鳥にするために、peg.js からいくつかのアイデアを盗んで純粋な Ruby PEG パーサー DSL を作成しました。違いは、peg.js は文法を JavaScript にコンパイルするのに対し、私のライブラリは Ruby が提供する構文シュガーと組み合わせたインタープリター パターンを使用して、すべてを純粋な Ruby で行うことです。これにより、回避したい重要なオーバーヘッドが追加されます。
オーバーヘッドの一部を削減するために、生成された構文解析式の一部を低レベルの表現にコンパイルすることを考え始めました。eval
私が思いついたアイデアの 1 つは、あるオブジェクトのシングルトン クラス内のコードの文字列表現を評価するために使用することでした。プロセスを示すための疑似コードを次に示します。
# will be used to pass CompiledExpression instance to `eval`
def get_binding(instance)
instance.instance_eval { binding }
end
# an instance of this class will be used with `eval`
# to define an `execute` method
class CompiledExpression
attr_reader :code_repr
# need to instantiate with a string representation of
# the code we are going to use to define the `execute` method
def initialize(code)
@code_repr = code
end
end
# create the instance and define `execute` for that instance
# by evaluating the code representation
compiled_expr = CompiledExpression.new
# first way
eval "class << self; def execute; " +
"#{compiled_expr.code_repr}; end; end", get_binding(compiled_expr)
# second way
compiled_expr.instance_eval "class << self; " +
"def execute; #{compiled_expr.code_repr}: end; end"
# third way
compiled_expr.singleton_class.class_eval "def execute; " +
"#{compiled_expr.code_repr}; end"
# fourth way
compiled_expr.instance_eval "def execute; " +
"#{compiled_expr.code_repr}; end"
そのようなコード生成を達成するための他の/より良いアプローチがあるかどうか知りたいですか? 私はこのようなことに慣れていないので、おそらく明らかな何かを見逃しています。