如何编写一个用参数创建函数的DSL?

时间:2018-06-10 03:05:19

标签: macros elixir metaprogramming dsl

我想定义一个宏,以便我可以将public bool useWorldSpace; public Rigidbody rb; public float speed = 18; public void Update() { float h = Input.GetAxisRaw("Horizontal"); float v = Input.GetAxisRaw("Vertical"); //Movement Vector3 tempVect = new Vector3(0, 0, v); tempVect = tempVect.normalized * speed * Time.deltaTime; if (useWorldSpace) tempVect = transform.position + tempVect; else tempVect = transform.position + transform.TransformDirection(tempVect); rb.MovePosition(tempVect); //Rotation Vector3 angle = new Vector3(0, 100, 0); Quaternion deltaRot = Quaternion.Euler(angle * h * Time.deltaTime); rb.MoveRotation(rb.rotation * deltaRot); } 块传递给它,并让宏创建一个调用块的函数,带有一个参数。我遇到了鸡肉和鸡肉。鸡蛋问题,因为下面的代码抱怨do没有定义。

name

尝试编译此代码会导致:

defmodule MyMacro do
  defmacro greet(do: block) do
    quote do
      def hello(name), do: unquote(block)
    end
  end
end

defmodule Test do
  import MyMacro
  greet do
    IO.puts("Hello, #{name}!")
  end
end

根据我的理解,这甚至在它到达我的宏之前就会爆炸,因为elixir在调用我的宏之前尝试为do块生成AST,但(CompileError) iex:6: undefined function name/0 (stdlib) lists.erl:1338: :lists.foreach/2 (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6 (iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5 未定义。

我的目标是能够在编译DSL后调用name。 Elixir有可能吗?

1 个答案:

答案 0 :(得分:2)

Elixir的宏是hygienic所以如果你在宏quote中声明一个变量,它就不会被调用者使用。您可以通过使用var!

包装变量的声明来禁用此功能
quote do
  def hello(var!(name)), do: unquote(block)
end