mirror of
https://github.com/foomo/gotsrpc.git
synced 2025-10-16 12:35:35 +00:00
276 lines
7.0 KiB
Go
276 lines
7.0 KiB
Go
package gotsrpc
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
var ReaderTrace = false
|
|
|
|
func readStructs(pkg *ast.Package) (structs map[string]*Struct, err error) {
|
|
structs = map[string]*Struct{}
|
|
for _, file := range pkg.Files {
|
|
//readFile(filename, file)
|
|
err = extractStructs(file, structs)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func trace(args ...interface{}) {
|
|
if ReaderTrace {
|
|
fmt.Fprintln(os.Stderr, args...)
|
|
}
|
|
}
|
|
|
|
func extractJSONInfo(tag string) *JSONInfo {
|
|
t := reflect.StructTag(tag)
|
|
jsonTagString := t.Get("json")
|
|
if len(jsonTagString) == 0 {
|
|
return nil
|
|
}
|
|
jsonTagParts := strings.Split(jsonTagString, ",")
|
|
|
|
name := ""
|
|
ignore := false
|
|
omit := false
|
|
forceStringType := false
|
|
cleanParts := []string{}
|
|
for _, jsonTagPart := range jsonTagParts {
|
|
cleanParts = append(cleanParts, strings.TrimSpace(jsonTagPart))
|
|
}
|
|
switch len(cleanParts) {
|
|
case 1:
|
|
switch cleanParts[0] {
|
|
case "-":
|
|
ignore = true
|
|
default:
|
|
name = cleanParts[0]
|
|
}
|
|
case 2:
|
|
if len(cleanParts[0]) > 0 {
|
|
name = cleanParts[0]
|
|
}
|
|
switch cleanParts[1] {
|
|
case "omitempty":
|
|
omit = true
|
|
case "string":
|
|
forceStringType = true
|
|
}
|
|
}
|
|
return &JSONInfo{
|
|
Name: name,
|
|
OmitEmpty: omit,
|
|
ForceStringType: forceStringType,
|
|
Ignore: ignore,
|
|
}
|
|
}
|
|
|
|
func getScalarFromAstIdent(ident *ast.Ident) ScalarType {
|
|
switch ident.Name {
|
|
case "string":
|
|
return ScalarTypeString
|
|
case "bool":
|
|
return ScalarTypeBool
|
|
case "int", "int32", "int64", "float", "float32", "float64":
|
|
return ScalarTypeNumber
|
|
default:
|
|
return ScalarTypeNone
|
|
}
|
|
}
|
|
|
|
func getTypesFromAstType(ident *ast.Ident) (structType string, scalarType ScalarType) {
|
|
scalarType = getScalarFromAstIdent(ident)
|
|
switch scalarType {
|
|
case ScalarTypeNone:
|
|
structType = ident.Name
|
|
}
|
|
return
|
|
}
|
|
|
|
func readAstType(v *Value, fieldIdent *ast.Ident) {
|
|
structType, scalarType := getTypesFromAstType(fieldIdent)
|
|
v.ScalarType = scalarType
|
|
|
|
if len(structType) > 0 {
|
|
v.StructType = &StructType{
|
|
Name: structType,
|
|
}
|
|
} else {
|
|
v.GoScalarType = fieldIdent.Name
|
|
}
|
|
}
|
|
|
|
func readAstStarExpr(v *Value, starExpr *ast.StarExpr) {
|
|
v.IsPtr = true
|
|
switch reflect.ValueOf(starExpr.X).Type().String() {
|
|
case "*ast.Ident":
|
|
ident := starExpr.X.(*ast.Ident)
|
|
v.StructType = &StructType{
|
|
Name: ident.Name,
|
|
}
|
|
case "*ast.StructType":
|
|
// nested anonymous
|
|
readAstStructType(v, starExpr.X.(*ast.StructType))
|
|
case "*ast.SelectorExpr":
|
|
readAstSelectorExpr(v, starExpr.X.(*ast.SelectorExpr))
|
|
default:
|
|
trace("a pointer on what", reflect.ValueOf(starExpr.X).Type().String())
|
|
}
|
|
}
|
|
|
|
func readAstArrayType(v *Value, arrayType *ast.ArrayType) {
|
|
switch reflect.ValueOf(arrayType.Elt).Type().String() {
|
|
case "*ast.StarExpr":
|
|
readAstStarExpr(v, arrayType.Elt.(*ast.StarExpr))
|
|
default:
|
|
trace("array type elt", reflect.ValueOf(arrayType.Elt).Type().String())
|
|
}
|
|
}
|
|
|
|
func readAstMapType(m *Map, mapType *ast.MapType) {
|
|
trace(" map key", mapType.Key, reflect.ValueOf(mapType.Key).Type().String())
|
|
trace(" map value", mapType.Value, reflect.ValueOf(mapType.Value).Type().String())
|
|
// key
|
|
switch reflect.ValueOf(mapType.Key).Type().String() {
|
|
case "*ast.Ident":
|
|
_, scalarType := getTypesFromAstType(mapType.Key.(*ast.Ident))
|
|
m.KeyType = string(scalarType)
|
|
}
|
|
// value
|
|
m.Value.loadExpr(mapType.Value)
|
|
}
|
|
|
|
func readAstSelectorExpr(v *Value, selectorExpr *ast.SelectorExpr) {
|
|
switch reflect.ValueOf(selectorExpr.X).Type().String() {
|
|
case "*ast.Ident":
|
|
// that could be the package name
|
|
selectorIdent := selectorExpr.X.(*ast.Ident)
|
|
v.StructType = &StructType{
|
|
Package: selectorIdent.Name,
|
|
Name: selectorExpr.Sel.Name,
|
|
}
|
|
default:
|
|
trace("selectorExpr.Sel !?", selectorExpr.X, reflect.ValueOf(selectorExpr.X).Type().String())
|
|
}
|
|
}
|
|
|
|
func readAstStructType(v *Value, structType *ast.StructType) {
|
|
v.Struct = &Struct{}
|
|
v.Struct.Fields = readFieldList(structType.Fields.List)
|
|
}
|
|
|
|
func (v *Value) loadExpr(expr ast.Expr) {
|
|
//fmt.Println(field.Names[0].Name, field.Type, reflect.ValueOf(field.Type).Type().String())
|
|
switch reflect.ValueOf(expr).Type().String() {
|
|
case "*ast.ArrayType":
|
|
fieldArray := expr.(*ast.ArrayType)
|
|
v.Array = &Array{Value: &Value{}}
|
|
switch reflect.ValueOf(fieldArray.Elt).Type().String() {
|
|
case "*ast.Ident":
|
|
readAstType(v.Array.Value, fieldArray.Elt.(*ast.Ident))
|
|
case "*ast.StarExpr":
|
|
readAstStarExpr(v.Array.Value, fieldArray.Elt.(*ast.StarExpr))
|
|
case "*ast.ArrayType":
|
|
readAstArrayType(v.Array.Value, fieldArray.Elt.(*ast.ArrayType))
|
|
case "*ast.MapType":
|
|
v.Array.Value.Map = &Map{
|
|
Value: &Value{},
|
|
}
|
|
readAstMapType(v.Array.Value.Map, fieldArray.Elt.(*ast.MapType))
|
|
default:
|
|
trace("---------------------> array of", reflect.ValueOf(fieldArray.Elt).Type().String())
|
|
}
|
|
case "*ast.Ident":
|
|
fieldIdent := expr.(*ast.Ident)
|
|
readAstType(v, fieldIdent)
|
|
case "*ast.StarExpr":
|
|
// a pointer on sth
|
|
readAstStarExpr(v, expr.(*ast.StarExpr))
|
|
case "*ast.MapType":
|
|
v.Map = &Map{
|
|
Value: &Value{},
|
|
}
|
|
readAstMapType(v.Map, expr.(*ast.MapType))
|
|
case "*ast.SelectorExpr":
|
|
readAstSelectorExpr(v, expr.(*ast.SelectorExpr))
|
|
case "*ast.StructType":
|
|
readAstStructType(v, expr.(*ast.StructType))
|
|
default:
|
|
trace("what kind of field ident would that be ?!", reflect.ValueOf(expr).Type().String())
|
|
}
|
|
}
|
|
|
|
func readField(astField *ast.Field) (name string, v *Value, jsonInfo *JSONInfo) {
|
|
name = ""
|
|
if len(astField.Names) > 0 {
|
|
name = astField.Names[0].Name
|
|
}
|
|
trace(" ", name)
|
|
v = &Value{}
|
|
v.loadExpr(astField.Type)
|
|
if astField.Tag != nil {
|
|
jsonInfo = extractJSONInfo(astField.Tag.Value[1 : len(astField.Tag.Value)-1])
|
|
}
|
|
return
|
|
}
|
|
|
|
func readFieldList(fieldList []*ast.Field) (fields []*Field) {
|
|
fields = []*Field{}
|
|
for _, field := range fieldList {
|
|
name, value, jsonInfo := readField(field)
|
|
|
|
if strings.Compare(strings.ToLower(name[:1]), name[:1]) == 0 {
|
|
continue
|
|
}
|
|
|
|
if value != nil {
|
|
fields = append(fields, &Field{
|
|
Name: name,
|
|
Value: value,
|
|
JSONInfo: jsonInfo,
|
|
})
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func extractStructs(file *ast.File, structs map[string]*Struct) error {
|
|
//for _, imp := range file.Imports {
|
|
// fmt.Println("import", imp.Name, imp.Path)
|
|
//}
|
|
for name, obj := range file.Scope.Objects {
|
|
//fmt.Println(name, obj.Kind, obj.Data)
|
|
if obj.Kind == ast.Typ && obj.Decl != nil {
|
|
//ast.StructType
|
|
structs[name] = &Struct{
|
|
Name: name,
|
|
Fields: []*Field{},
|
|
}
|
|
if reflect.ValueOf(obj.Decl).Type().String() == "*ast.TypeSpec" {
|
|
typeSpec := obj.Decl.(*ast.TypeSpec)
|
|
typeSpecRefl := reflect.ValueOf(typeSpec.Type)
|
|
if typeSpecRefl.Type().String() == "*ast.StructType" {
|
|
structType := typeSpec.Type.(*ast.StructType)
|
|
trace("StructType", obj.Name)
|
|
structs[name].Fields = readFieldList(structType.Fields.List)
|
|
} else {
|
|
// fmt.Println(" what would that be", typeSpecRefl.Type().String())
|
|
}
|
|
} else {
|
|
//fmt.Println(" !!!!!!!!!!!!!!!!!!!!!!!!!!!! not a type spec", r.Type().String())
|
|
}
|
|
} else if obj.Kind == ast.Fun {
|
|
//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> a fucking func / method", obj.Kind, obj)
|
|
} else {
|
|
//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", obj.Kind, obj)
|
|
}
|
|
}
|
|
return nil
|
|
}
|