英文:
How to print hand-written AST?
问题
我有一组描述网络协议的XML文件,我想要从中生成Go代码,因此我没有任何现有的Go代码可供使用。所有使用go/ast
(例如go fmt
)的示例都是基于现有代码进行一些AST转换,然后再将其写回。由于我只有XML文件,所以我必须手动编写AST。问题是,我无法让我手写的AST输出。
期望输出:
package foo
type Bar uint32
实际输出:没有任何输出
我该如何让AST输出呢?
英文:
I have a set of XML description of network protocol that I'm trying to generate Go code from, therefore I don't have any existing Go code to work with. All of the examples that make use of go/ast
(such as go fmt
) take existing code, do some transformation on the AST, then write them back out. Since all I have are XML files, the AST that I'm working with have to be written by hand. The problem is that I cannot get my hand-written AST to output.
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)
}
Expected output:
package foo
type Bar uint32
Actual output: nothing
How do I get the AST to print?
答案1
得分: 6
不要忽视错误!
添加:
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)
}
}
英文:
Don't ignore errors!
Adding:
err := printer.Fprint(os.Stdout, fset, f)
if err != nil {
log.Fatal(err)
}
Gives: "go/printer: unsupported node type ast.File" which should have been enough to point you in the right direction.
printer.Fprint
's last argument is interface{}
so the compiler accepts anything. However, just as parser.ParseFile
returns an *ast.File
(rather than ast.File
) it expects a pointer to a node.
Passing a pointer gives the output you want (note the &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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论