将复杂参数传递给Nimrod宏

时间:2013-12-18 10:21:53

标签: macros compile-time nimrod nim

我想将配置参数传递给宏。我已经有一个基于这些参数(一个序列元组)产生一串Nimrod代码的过程。 我知道我可以传递一个字符串并将其转换为strVal(如答案https://stackoverflow.com/a/19956317/334703所示)。我可以用更复杂的数据做同样的事吗?

或者,我可以在编译时程序中使用此字符串的Nimrod代码,并调用parseStmt等过程吗?

编辑: Nimrod代码的生成对于测试我的想法很有用,我同意我应该直接生成AST。

以下是我正在考虑的结构示例。

type
  Tconfig = tuple
    letters: seq[string]
    numbers:seq[int]

var
  data = (@("aa", "bb"), @(11, 22))

macro mymacro(data: Tconfig): stmt =
   ...

3 个答案:

答案 0 :(得分:2)

如果你的宏需要处理传递给它的实际常量数据,推荐的方法是使用静态参数:

type
  TConfig = tuple
    letters: seq[string]
    numbers:seq[int]

const data = (@["aa", "bb"], @[11, 22])

macro mymacro(cfg: static[TConfig]): stmt =
  echo "letters"
  for s in cfg.letters:
    echo s

  echo "numbers"
  for n in cfg.numbers:
    echo n

mymacro(data)

这种方法有很多好处:

1)输入参数cfg不是获取原始AST,而是在宏体内部具有TConfig类型,因此您可以更轻松地访问其成员,如示例所示。

2)编译器将自动评估产生TConfig值的复杂表达式,当它们与宏一起使用时(例如mymacro(mergeConfigs(userConfig, systemConfig)),假设mergeConfigs是一些可以评估的proc在编译时。)

有关静态参数的更多信息,请参阅手册:
http://nim-lang.org/manual.html#static-t

答案 1 :(得分:1)

我不是100%肯定你的意思,但从上下文来看,你看起来好像你需要的功能是macros.toStrLit,它从AST生成一个字符串文字节点。例如:

import macros, strutils

macro showExpr(x: expr): stmt =
  parseStmt("echo(" & x.toStrLit.strVal.escape & ")")

showExpr("x" & "y")

考虑直接转换AST,因为生成和重新分析代码作为字符串可能会引发意外(请注意上面的.escape),缩进等。

答案 2 :(得分:1)

如果您需要或想要遍历宏中数据的结构,首先需要将变量设为constvar用于运行时,因此宏将获得nnkSym节点。一旦你创建了const,就会获得相同的输入,就像你在那里手动输入值一样。我将使用treeRepr宏和大量echo来向您展示您获得的AST类型以及如何使用它:

import macros

type
  Tconfig = tuple
    letters: seq[string]
    numbers:seq[int]

const data: Tconfig = (@["aa", "bb"], @[11, 22])

macro mymacro(data: Tconfig): stmt =
  echo "AST being passed in:\n", treeRepr(data)
  echo "root type is ", data.kind
  echo "number of children ", len(data)
  let n1 = data[0]
  echo "first child is ", n1.kind
  echo "first child children ", len(n1)
  let e2 = n1[1]
  echo "second exp child is ", e2.kind
  echo "second exp child children ", len(e2)
  let v1 = e2[0]
  echo "first seq value is ", v1.kind
  echo "first seq value children ", len(v1)
  echo "Final literal is ", v1.strVal

when isMainModule:
  mymacro(data)

当我编译该示例时,我得到以下输出:

AST being passed in:
Par
  ExprColonExpr
    Sym "letters"
    Bracket
      StrLit aa
      StrLit bb
  ExprColonExpr
    Sym "numbers"
    Bracket
      IntLit 11
      IntLit 22
root type is nnkPar
number of children 2
first child is nnkExprColonExpr
first child children 2
second exp child is nnkBracket
second exp child children 2
first seq value is nnkStrLit
first seq value children 0
Final literal is aa