代码之家  ›  专栏  ›  技术社区  ›  user1698814

如何打印手写AST?

  •  1
  • user1698814  · 技术社区  · 10 年前

    我有一组网络协议的XML描述,我试图从中生成Go代码,因此我没有任何现有的Go代码可以使用。所有使用 go/ast (例如 go fmt )使用现有代码,对AST进行一些转换,然后将它们写出来。因为我只有XML文件,所以我使用的AST必须手动编写。问题是我无法将手写的AST输出。

    Example

    package main
    
    import (
        "go/ast"
        "go/printer"
        "go/token"
        "os"
    )
    
    func main() {
        f := ast.File{
            Name: ast.NewIdent("foo"),
            Decls: []ast.Decl{
                &ast.GenDecl{
                    Tok: token.TYPE,
                    Specs: []ast.Spec{
                        &ast.TypeSpec{
                            Name: ast.NewIdent("Bar"),
                            Type: ast.NewIdent("uint32"),
                        },
                    },
                },
            },
        }
        fset := token.NewFileSet()
        printer.Fprint(os.Stdout, fset, f)
    }
    

    预期输出:

    package foo
    
    type Bar uint32
    

    实际输出:无

    如何打印AST?

    1 回复  |  直到 10 年前
        1
  •  6
  •   Dave C    10 年前

    不要忽略错误!

    添加:

    err := printer.Fprint(os.Stdout, fset, f)
    if err != nil {
        log.Fatal(err)
    }
    

    给出:“ go/printer:不支持的节点类型ast.File “这应该足以给你指明正确的方向。

    printer.Fprint 的最后一个参数是 interface{} 所以编译器接受任何东西。然而,正如 parser.ParseFile 返回一个 *ast.File (而不是 ast.File )它需要指向节点的指针。

    传递一个指针可以得到所需的输出(注意 &ast.File ):

    package main
    
    import (
        "go/ast"
        "go/printer"
        "go/token"
        "log"
        "os"
    )
    
    func main() {
        f := &ast.File{
            Name: ast.NewIdent("foo"),
            Decls: []ast.Decl{
                &ast.GenDecl{
                    Tok: token.TYPE,
                    Specs: []ast.Spec{
                        &ast.TypeSpec{
                            Name: ast.NewIdent("Bar"),
                            Type: ast.NewIdent("uint32"),
                        },
                    },
                },
            },
        }
        fset := token.NewFileSet()
        err := printer.Fprint(os.Stdout, fset, f)
        if err != nil {
            log.Fatal(err)
        }
    }
    

    playground