github.com/mlmmr/revel-cmd@v0.21.2-0.20191112133115-68d8795776dd/model/type_expr.go (about) 1 package model 2 3 // TypeExpr provides a type name that may be rewritten to use a package name. 4 import ( 5 "fmt" 6 "go/ast" 7 ) 8 9 type TypeExpr struct { 10 Expr string // The unqualified type expression, e.g. "[]*MyType" 11 PkgName string // The default package idenifier 12 pkgIndex int // The index where the package identifier should be inserted. 13 Valid bool 14 } 15 16 // Returns a new type from the data 17 func NewTypeExprFromData(expr, pkgName string, pkgIndex int, valid bool) TypeExpr { 18 return TypeExpr{expr, pkgName, pkgIndex, valid} 19 } 20 21 // NewTypeExpr returns the syntactic expression for referencing this type in Go. 22 func NewTypeExprFromAst(pkgName string, expr ast.Expr) TypeExpr { 23 error := "" 24 switch t := expr.(type) { 25 case *ast.Ident: 26 if IsBuiltinType(t.Name) { 27 pkgName = "" 28 } 29 return TypeExpr{t.Name, pkgName, 0, true} 30 case *ast.SelectorExpr: 31 e := NewTypeExprFromAst(pkgName, t.X) 32 return NewTypeExprFromData(t.Sel.Name, e.Expr, 0, e.Valid) 33 case *ast.StarExpr: 34 e := NewTypeExprFromAst(pkgName, t.X) 35 return NewTypeExprFromData("*"+e.Expr, e.PkgName, e.pkgIndex+1, e.Valid) 36 case *ast.ArrayType: 37 e := NewTypeExprFromAst(pkgName, t.Elt) 38 return NewTypeExprFromData("[]"+e.Expr, e.PkgName, e.pkgIndex+2, e.Valid) 39 case *ast.MapType: 40 if identKey, ok := t.Key.(*ast.Ident); ok && IsBuiltinType(identKey.Name) { 41 e := NewTypeExprFromAst(pkgName, t.Value) 42 return NewTypeExprFromData("map["+identKey.Name+"]"+e.Expr, e.PkgName, e.pkgIndex+len("map["+identKey.Name+"]"), e.Valid) 43 } 44 error = fmt.Sprintf("Failed to generate name for Map field :%v. Make sure the field name is valid.", t.Key) 45 case *ast.Ellipsis: 46 e := NewTypeExprFromAst(pkgName, t.Elt) 47 return NewTypeExprFromData("[]"+e.Expr, e.PkgName, e.pkgIndex+2, e.Valid) 48 default: 49 error = fmt.Sprintf("Failed to generate name for field: %v Package: %v. Make sure the field name is valid.", expr, pkgName) 50 51 } 52 return NewTypeExprFromData(error, "", 0, false) 53 } 54 55 // TypeName returns the fully-qualified type name for this expression. 56 // The caller may optionally specify a package name to override the default. 57 func (e TypeExpr) TypeName(pkgOverride string) string { 58 pkgName := FirstNonEmpty(pkgOverride, e.PkgName) 59 if pkgName == "" { 60 return e.Expr 61 } 62 return e.Expr[:e.pkgIndex] + pkgName + "." + e.Expr[e.pkgIndex:] 63 } 64 65 var builtInTypes = map[string]struct{}{ 66 "bool": {}, 67 "byte": {}, 68 "complex128": {}, 69 "complex64": {}, 70 "error": {}, 71 "float32": {}, 72 "float64": {}, 73 "int": {}, 74 "int16": {}, 75 "int32": {}, 76 "int64": {}, 77 "int8": {}, 78 "rune": {}, 79 "string": {}, 80 "uint": {}, 81 "uint16": {}, 82 "uint32": {}, 83 "uint64": {}, 84 "uint8": {}, 85 "uintptr": {}, 86 } 87 88 // IsBuiltinType checks the given type is built-in types of Go 89 func IsBuiltinType(name string) bool { 90 _, ok := builtInTypes[name] 91 return ok 92 } 93 94 // Returns the first non empty string from a list of arguements 95 func FirstNonEmpty(strs ...string) string { 96 for _, str := range strs { 97 if len(str) > 0 { 98 return str 99 } 100 } 101 return "" 102 }