2015-01-02 38 views
1

我需要一个语句列表分为多个部分,像这样:声明列表组成

import macros 

macro test: stmt = 
    var first = quote do: 
     var x = 1 
    var second = quote do: 
     echo x 
    result = newStmtList() 
    first.copyChildrenTo(result) 
    second.copyChildrenTo(result) 

    echo result.repr 

test 

但是,编译器告诉我:

[..] 

    var x = 1 
    echo x 
minimalist.nim(14, 0) Info: instantiation from here 
minimalist.nim(7, 13) Error: undeclared identifier: 'x' 
      echo x 

这是非常混乱因为x声明在节点列表中。我如何正确地完成这项工作? (如果不是很明显,我确实需要AST拆分成其他原因的多个部分)

回答

3

默认情况下,净息差执行宏引用块内代码的卫生规则。这意味着一个块中引入的符号名称在另一个块中不可见。您可以通过引入变量这样的共享符号解决这个问题:

import macros 

macro test: stmt = 
    var x = genSym() 

    var first = quote do: 
     var `x` = 1 

    var second = quote do: 
     echo `x` 

    result = newStmtList() 
    first.copyChildrenTo(result) 
    second.copyChildrenTo(result) 

test 

引擎盖下,报价由施加到非脏模板getAst操作供电。如果你自己使用较低级别的机制,它也可以禁用像这样的报价模板的卫生习惯:

import macros 

macro test: stmt = 
    template first {.dirty.} = 
    var x = 1 

    template second {.dirty.} = 
    echo x 

    result = newStmtList() 
    getAst(first()).copyChildrenTo(result) 
    getAst(second()).copyChildrenTo(result) 

test 

这将得到相同的结果。请记住,quote最终会获得一个控制引用代码脏乱的标志。

2

如果比较的AST,你可以看到什么错:

dumpTree: 
    var x = 1 
    echo x 

此打印:

StmtList 
    VarSection 
    IdentDefs 
     Ident !"x" 
     Empty 
     IntLit 1 
    Command 
    Ident !"echo" 
    Ident !"x" 

然后在你的榜样:

macro test: stmt = 
    var first = quote do: 
     var x = 1 
    var second = quote do: 
     echo x 

    result = newStmtList() 
    first.copyChildrenTo(result) 
    second.copyChildrenTo(result) 

    echo result.treeRepr 

test 

此打印:

StmtList 
    VarSection 
    IdentDefs 
     Sym "x" 
     Empty 
     IntLit 1 
    Command 
    Sym "echo" 
    Ident !"x" 

注意区别?一旦“x”是一个Ident,另一次是Sym。这些符号不应该被查找,也许这应该在编译器中进行更改。但现在你可以帮忙自己,再次更换Idents所有西姆斯,以强制执行新的查找:

import macros 

proc symsToIdents(n): PNimrodNode {.compiletime.} = 
    if n.kind == nnkSym: 
     return newIdentNode($n) 

    result = n 
    for i in 0 .. <result.len: 
     result[i] = symsToIdents(n[i]) 

macro test: stmt = 
    var first = quote do: 
     var x = 1 
    var second = quote do: 
     echo x 

    result = newStmtList() 
    first.copyChildrenTo(result) 
    second.copyChildrenTo(result) 
    result = symsToIdents(result) 

test 

编辑:报告为现在一个可能的错误:https://github.com/nim-lang/Nim/issues/1843

+0

这正是我需要使我的代码工作,但我觉得这是一个编译器/标准库错误 –