【问题标题】:how to update an AST without breaking the code when it contains comments如何在包含注释的情况下更新 AST 而不会破坏代码
【发布时间】:2019-11-20 13:09:12
【问题描述】:

鉴于此代码,我如何在不破坏 cmets 节点的情况下使用额外的导入规范打印它。

在下面的代码中,我使用包加载器 API 从字符串加载包。我尝试使用生成的 AST 来插入一个新节点,一个导入规范。

不幸的是,当我尝试打印修改后的 AST 时,cmets 被打乱了。

https://play.golang.org/p/N6_y1ehM1Qc

package main

import (
    "go/ast"
    "go/parser"
    "go/printer"
    "go/token"
    "log"
    "os"

    "golang.org/x/tools/go/loader"
)

func main() {

    var conf loader.Config
    conf.ParserMode = parser.ParseComments

    f, err := conf.ParseFile("main.go", `// some comment goes here 
package main

// some comment here.

// main comment here.
func main(){
}
`)
    if err != nil {
        log.Fatal(err)
    }
    conf.CreateFromFiles("main", f)
    prog, err := conf.Load()
    if err != nil {
        log.Println(err)
    }

    g := &ast.GenDecl{}
    g.Tok = token.IMPORT
    spec := &ast.ImportSpec{
        Path: &ast.BasicLit{Value: "package/path"},
    }
    g.Specs = append(g.Specs, spec)
    f.Decls = append([]ast.Decl{g}, f.Decls...)
    _ = prog
    printer.Fprint(os.Stdout, token.NewFileSet(), f)
    //printer.Fprint(os.Stdout, prog.Fset, f)
}

这个程序输出

package main // some comment goes here
// some comment here.
// main comment here.
import package/path

func main() {
}

我希望得到这个结果:

// some comment goes here
package main

// some comment here.
import package/path

// main comment here.
func main() {
}

这是有问题的,因为在更复杂的程序中,输出会被破坏:

// some comment goes here
package main

import // some comment here.
package/path

// main comment here.
func main() {
}

【问题讨论】:

  • 您可以使用现有的FileSet 以避免所有内容放错位置,然后为导入声明设置所需的token.Posplay.golang.org/p/hCLQB3daxOF
  • 你有什么建议降下树来调整新插入节点之后每个元素的位置吗?我做了更多的测试,在我看来,只使用参考和添加/删除偏移量是有风险的。
  • 也许可以尝试使用golang.org/x/tools/go/ast/astutil 并查看它的来源,看看它是如何计算位置的。不能说更多,因为我自己从未使用过。
  • 谢谢,我忘记了 astutil。确实应该有帮助。
  • 我们遇到了同样的问题。我认为 ast 包文档应该更新一下。 (我们最终选择了完全不同的方式)

标签: go abstract-syntax-tree


【解决方案1】:

感谢@mkopriva 的建议,我能够使用astutil.AddImport 解决该问题。

astutil.AddImport(prog.Fset, f, "package/path")

我的原始代码中的问题是我没有正确更新节点的位置。

如果您打开this link,您可以阅读更多关于幕后发生的事情以及为了正确插入节点而必须解决的各种用例。您可以在 cmets 阅读并了解正在发生的事情。

【讨论】:

    猜你喜欢
    • 2018-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 2022-10-02
    • 2010-12-21
    • 1970-01-01
    相关资源
    最近更新 更多