2013-12-18 240 views
0

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

回答

1

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

非常感谢。这个例子非常有用。 –

1

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

import macros, strutils 

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

showExpr("x" & "y") 

考虑直接转化AST,不过,因为生成和重新分析代码串可导致意外使用引号(注意上面的.escape),压痕等

+0

感谢您对这些第一信息。我编辑了这个问题,试图更清晰。 –

2

如果您的宏需要处理传递给它的实际恒定的数据,推荐的方法是使用静态PARAMS:

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)代替获取原始AST,输入参数cfg在宏体内将有TConfig类型,因此您可以更轻松地访问其成员,如示例中所示。

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

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