【问题标题】:Passing complex parameters to a Nimrod macro将复杂参数传递给 Nimrod 宏
【发布时间】:2013-12-18 10:21:52
【问题描述】:

我想将配置参数传递给宏。我已经有一个基于这些参数(序列元组)生成一串 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 =
   ...

【问题讨论】:

    标签: macros compile-time nim-lang


    【解决方案1】:

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

    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 将在宏体内具有 TConfig 类型,而不是获取原始 AST,因此您可以更轻松地访问其成员,如示例所示。

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

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

    【讨论】:

      【解决方案2】:

      如果需要或者想遍历宏中数据的结构,首先需要将变量设为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
      

      【讨论】:

      • 非常感谢。这个例子真的很有用。
      【解决方案3】:

      我不能 100% 确定您的意思,但从上下文来看,您需要的功能似乎是 macros.toStrLit 的功能,它从 AST 生成字符串文字节点。示例:

      import macros, strutils
      
      macro showExpr(x: expr): stmt =
        parseStmt("echo(" & x.toStrLit.strVal.escape & ")")
      
      showExpr("x" & "y")
      

      但请考虑直接转换 AST,因为将代码生成和重新解析为字符串可能会导致出现意外的引用(请注意上面的 .escape)、缩进等。

      【讨论】:

      • 感谢您提供这些第一信息。我已经编辑了问题以使其更清楚。
      猜你喜欢
      • 2014-04-01
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多