Adi*_*tya 5 abstract-syntax-tree go iota
我一直在与 go/ast 合作来解析 go 源代码并将其复制到另一个文件中,作为供应商练习的一部分。我已经处理了大部分事情 - 函数、类型等 - 但我正在努力处理使用 iota 的 const 声明。我正在迭代 ast.File.Scope.Objects 中的项目,并复制 Scope.Outer == nil 及其 Decl == ast.ValueSpec 的对象的源代码,基本上意味着顶级变量和常量。
在类型块中:
const (
a = iota
b
c
d
)
Run Code Online (Sandbox Code Playgroud)
...它们中的每一个都注册为一个单独的对象,这很公平。但是,我很难为它们分配值,因为当我迭代它们时,对象也可能乱序。我可以将这些值视为 ast.Object.Data,但当它设置为 1 << iota 等时,它似乎也关闭了。有人对如何获得分配了正确 iota 值的分组 const 声明有任何想法吗?
谢谢你!
我正在为分析器解决这个问题exhaustive,分析器在枚举发现阶段需要找到常量值。
游乐场: https://play.golang.org/p/nZLmgE4rJZH
考虑以下 ConstDecl。它由3个ConstSpec组成,每个ConstSpec有2个名称。(本示例使用 iota,但下面的方法通常适用于任何 ConstDecl。)
package example
const (
A, B = iota, iota * 100 // 0, 0
_, D // 1, 100
E, F // 2, 200
)
Run Code Online (Sandbox Code Playgroud)
通过go/ast和go/types(或x/tools/go/packages),我们可以获得代表上述 ConstDecl 的 *ast.GenDecl 和包的 *types.Info 。
var decl *ast.GenDecl
var info *types.Info
Run Code Online (Sandbox Code Playgroud)
以下情况将适用于decl。
decl.Tok == token.CONST
Run Code Online (Sandbox Code Playgroud)
为了获得常数值,我们可以这样做:
decl.Tok == token.CONST
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,这将打印:
A 0
B 0
_ 1
D 100
E 2
F 200
Run Code Online (Sandbox Code Playgroud)
var代替const请注意,上面的代码适用于const块;对于一个var块,我们必须使用v.Values[i](假设索引处存在值i)来获取值。
游乐场:https://play.golang.org/p/f4mYjXvsvHB
decl.Tok == token.VAR
Run Code Online (Sandbox Code Playgroud)
func printValuesVar(decl *ast.GenDecl, info *types.Info) {
for _, s := range decl.Specs {
v := s.(*ast.ValueSpec) // safe because decl.Tok == token.VAR
for i, name := range v.Names {
if len(v.Values) <= i {
fmt.Println(name, "(no AST value)")
continue
}
tv := info.Types[v.Values[i]]
if tv.Value == nil {
fmt.Println(name, "(not constant value)")
continue
}
fmt.Println(name, tv.Value.ExactString())
}
}
}
Run Code Online (Sandbox Code Playgroud)