How do you get an *ast.Package?

agolangf · · 426 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>No, really. How do you get one?</p> <p>According to <code>go doc go/ast | grep Package</code>...</p> <pre><code>Package ast declares the types used to represent syntax trees for Go func FilterPackage(pkg *Package, f Filter) bool func PackageExports(pkg *Package) bool func MergePackageFiles(pkg *Package, mode MergeMode) *File type Package struct{ ... } func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, ...) (*Package, error) </code></pre> <p>...there&#39;s only one way:</p> <pre><code>func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) </code></pre> <p>I tried passing nil for importer and universe, but I got parse errors like &#34;undeclared name: string&#34;. So, how do I get an ast.Importer and the universe *ast.Scope that will work in the general case?</p> <p>I grepped stdlib and golang.org/x/tools code and found an ast.Importer implementation called &#34;poorMansImporter&#34;, but the code indicates it&#39;s a half-assed implementation that does some guesswork. It doesn&#39;t seem generally useful.</p> <p>I see a types.Universe, which is a *types.Scope, but I need an *ast.Scope. And there&#39;s no ast.Universe *ast.Scope.</p> <p>Argh! Help! :)</p> <hr/>**评论:**<br/><br/>zekjur: <pre><p>Check out <a href="http://golang.org/s/types-tutorial">http://golang.org/s/types-tutorial</a>, specifically <a href="https://github.com/golang/example/tree/master/gotypes#an-example">https://github.com/golang/example/tree/master/gotypes#an-example</a> :)</p></pre>zekjur: <pre><p>If you’re using Go ≥ 1.9, <code>importer.For(&#34;source&#34;, nil)</code> is the most useful/correct importer (because it doesn’t require up-to-date export data files to be present), but also slower than <code>importer.Default()</code>.</p></pre>sh41: <pre><p>I&#39;ve been looking for an answer for the last 4 years too. This is the best I&#39;ve found. But I&#39;m still looking for a better way.</p> <p><a href="https://github.com/shurcooL/cmd/blob/3775d1a67e78fba6a8380e30337340465a0b30e3/gorepogen/main.go#L80-L93" rel="nofollow">https://github.com/shurcooL/cmd/blob/3775d1a67e78fba6a8380e30337340465a0b30e3/gorepogen/main.go#L80-L93</a></p></pre>indil7: <pre><p>Ha, that&#39;s EXACTLY what I did as a workaround! That&#39;s funny. :)</p> <p>It leaves ast.Package.Imports empty, though, and, presumably, as the NewPackage doc says, undeclared identifiers unresolved. I was hoping to do it the &#34;right&#34; way, if you know what I mean.</p> <p>Edit: I think there&#39;s a Package.Scope that it also leaves nil.</p></pre>sh41: <pre><p>Yes, I know what you mean. I haven&#39;t found a better way but will gladly update my code if I ever do.</p> <p>That said, the main question is what do you need the *ast.Package for? If it&#39;s for creating a *doc.Package, the above fields should be sufficient. As far as I know, there&#39;s no other use for *ast.Package.</p> <p>For all other things, you&#39;ll either use go/build to get a *build.Package, or use go/types if you want to do type analysis.</p></pre>indil7: <pre><p>It&#39;s for code generation, so I need the full AST. Another use might be something like gofmt or other syntax transformations.</p></pre>matttproud: <pre><p>I recommend looking at cmd/vet or cmd/lint source as an example. They are an easy read: <a href="https://github.com/golang/go/tree/master/src/cmd/vet" rel="nofollow">https://github.com/golang/go/tree/master/src/cmd/vet</a></p></pre>daydreamdrunk: <pre><p>I usually use parser.ParseDir like this: </p> <p><a href="https://play.golang.org/p/nbqLAolgbT" rel="nofollow">https://play.golang.org/p/nbqLAolgbT</a></p> <p>Though it does not run on the playground, complaining that $GOPATH&#39;s not set. </p></pre>indil7: <pre><p>The problem with that approach is that it doesn&#39;t work for packages with build tags. For example, for package runtime: &#34;cannot load package: [...]/src/runtime/defs1_netbsd_arm.go:7:2: _EINTR redeclared in this block&#34;. Do you know a way around that for ParseDir?</p></pre>daydreamdrunk: <pre><p>The go/build portion in that listing takes care of all that</p> <p>Edit to clarify: it handles all the stuff with gopath and build tags and gives a list of the files that apply to the given build.Context (which defaults to the default context which is the current GOOS/GOARCH).</p> <p>Note the fileCheck closure: it tells ParseDir to only parse the files which go/build identifies. (It would be really nice if this were helper on build.Package or there was a helper func in parse, but it&#39;s not a lot of code to write.)</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

426 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传