解析 Golang 变量
Parse Golang variables
我正在尝试静态分析 Go 文件。为此,我需要解析以下格式的变量:
shape.color = color.red
我需要找到所有使用点表示法访问的变量。例如,我需要知道 shape 变量具有 color 属性。并且还需要颜色变量具有红色属性。
我正在尝试使用 go/ast 和 go/parser 包,但无法找到一种方法。
N.B。如果它是类似于 shape.color() 的东西,即一种方法,那么它不应该被计算在内
您似乎在尝试创建自己的 AST,因为您给出的表达式的右侧看起来不像是变量,否则我将其假定为结构。然而,这也没有意义,因为将名为 red
的字段放在名为 color
的结构中实际上是不合逻辑的。似乎您正在尝试访问包的变量,但这也行不通,因为首字母小写意味着该实体未导出。
撇开所有这些,我写了一小段只是为了遵守您列出的条件。
- 形状变量具有颜色属性。
- 颜色变量有红色属性。
https://play.golang.org/p/gIpctQ1XSgT,我只为一行修改了它,并在不满足简洁性条件时感到恐慌。随意根据您的需要进行调整。
package main
import (
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
)
func main() {
expr, err := parser.ParseExpr("shape.color==color.red")
if err != nil {
panic(err)
}
// Checking if the expression was binary.
bExpr, ok := expr.(*ast.BinaryExpr)
if !ok {
panic("expr is not a binary expr.")
}
// If the operation is not “==”, die.
if bExpr.Op != token.EQL {
panic("the op should have been ==.")
}
// Left must be a selector expr, meaning followed with a selector which is “dot” in this case.
left, ok := bExpr.X.(*ast.SelectorExpr)
if !ok {
panic("left should have been a selector expr.")
}
// Same as above.
right, ok := bExpr.Y.(*ast.SelectorExpr)
if !ok {
panic("right should have been a selector expr.")
}
// Checking for attributes.
if left.Sel.Name != "color" {
panic("left should have had a color attr.")
}
// Same as above.
if right.Sel.Name != "red" {
panic("right should have had a red attr.")
}
// Then we finally gofmt the code and print it to stdout.
if err := format.Node(os.Stdout, token.NewFileSet(), expr); err != nil {
panic(err)
}
}
如果你正在比较两个你事先不知道的go变量,你将需要使用反射。这将使您能够反思性地比较这两个字段:
type color struct {
Red string
}
type shape struct {
Color string
}
func main() {
color := color{Red: "red"}
shape := shape{Color: "red"}
colorVal := reflect.ValueOf(color)
shapeVal := reflect.ValueOf(shape)
colorRedField := colorVal.FieldByName("Red")
shapeColorField := shapeVal.FieldByName("Color")
fmt.Println(colorRedField)
fmt.Println(shapeColorField)
fmt.Println(colorRedField.Interface() == shapeColorField.Interface())
}
啊!下面的代码打印了所有用点号访问的变量!
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
)
func main() {
v := visitor{}
filename := "test.go"
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filename, nil, 0)
if err != nil {
log.Fatal(err)
}
ast.Walk(&v, f)
}
type visitor struct {
}
func (v *visitor) Visit(n ast.Node) ast.Visitor {
if n == nil {
return v
}
if selectorExp, ok := n.(*ast.SelectorExpr); ok {
if x, ok := selectorExp.X.(*ast.Ident); ok {
if x.Obj == nil {
return v
}
fmt.Printf("%s.%s\n", x.Name, selectorExp.Sel.Name)
}
}
return v
}
我正在尝试静态分析 Go 文件。为此,我需要解析以下格式的变量:
shape.color = color.red
我需要找到所有使用点表示法访问的变量。例如,我需要知道 shape 变量具有 color 属性。并且还需要颜色变量具有红色属性。 我正在尝试使用 go/ast 和 go/parser 包,但无法找到一种方法。
N.B。如果它是类似于 shape.color() 的东西,即一种方法,那么它不应该被计算在内
您似乎在尝试创建自己的 AST,因为您给出的表达式的右侧看起来不像是变量,否则我将其假定为结构。然而,这也没有意义,因为将名为 red
的字段放在名为 color
的结构中实际上是不合逻辑的。似乎您正在尝试访问包的变量,但这也行不通,因为首字母小写意味着该实体未导出。
撇开所有这些,我写了一小段只是为了遵守您列出的条件。
- 形状变量具有颜色属性。
- 颜色变量有红色属性。
https://play.golang.org/p/gIpctQ1XSgT,我只为一行修改了它,并在不满足简洁性条件时感到恐慌。随意根据您的需要进行调整。
package main
import (
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
)
func main() {
expr, err := parser.ParseExpr("shape.color==color.red")
if err != nil {
panic(err)
}
// Checking if the expression was binary.
bExpr, ok := expr.(*ast.BinaryExpr)
if !ok {
panic("expr is not a binary expr.")
}
// If the operation is not “==”, die.
if bExpr.Op != token.EQL {
panic("the op should have been ==.")
}
// Left must be a selector expr, meaning followed with a selector which is “dot” in this case.
left, ok := bExpr.X.(*ast.SelectorExpr)
if !ok {
panic("left should have been a selector expr.")
}
// Same as above.
right, ok := bExpr.Y.(*ast.SelectorExpr)
if !ok {
panic("right should have been a selector expr.")
}
// Checking for attributes.
if left.Sel.Name != "color" {
panic("left should have had a color attr.")
}
// Same as above.
if right.Sel.Name != "red" {
panic("right should have had a red attr.")
}
// Then we finally gofmt the code and print it to stdout.
if err := format.Node(os.Stdout, token.NewFileSet(), expr); err != nil {
panic(err)
}
}
如果你正在比较两个你事先不知道的go变量,你将需要使用反射。这将使您能够反思性地比较这两个字段:
type color struct {
Red string
}
type shape struct {
Color string
}
func main() {
color := color{Red: "red"}
shape := shape{Color: "red"}
colorVal := reflect.ValueOf(color)
shapeVal := reflect.ValueOf(shape)
colorRedField := colorVal.FieldByName("Red")
shapeColorField := shapeVal.FieldByName("Color")
fmt.Println(colorRedField)
fmt.Println(shapeColorField)
fmt.Println(colorRedField.Interface() == shapeColorField.Interface())
}
啊!下面的代码打印了所有用点号访问的变量!
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
)
func main() {
v := visitor{}
filename := "test.go"
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filename, nil, 0)
if err != nil {
log.Fatal(err)
}
ast.Walk(&v, f)
}
type visitor struct {
}
func (v *visitor) Visit(n ast.Node) ast.Visitor {
if n == nil {
return v
}
if selectorExp, ok := n.(*ast.SelectorExpr); ok {
if x, ok := selectorExp.X.(*ast.Ident); ok {
if x.Obj == nil {
return v
}
fmt.Printf("%s.%s\n", x.Name, selectorExp.Sel.Name)
}
}
return v
}