2017-09-28 10 views
0

状況チェック式は構造体のフィールドをチェックするコードジェネレータを書い

「/パーサを行く」と構造体タグに

問題

を使用して、検証機能を追加使用して、カスタムタイプがある場合

ここで私は

、タイプフィールドは、カスタムタイプか

すなわちであるかどうかを確認する必要があります3210

続いて[、カスタムタイプ

int, []int,*int,[]Integer,map[string]PhoneNumber 

はありませんが、次は私が完全一致を探して、マップを追加することができ、次のような関数を使用してそれを行うことができると思いますカスタムタイプ

Integer,PhoneNumber,*PhoneNumber 

です]サポート

func isBuiltInType(typ string) bool { 
    switch typ { 
      case "bool", "byte", "complex128", "complex64", "error": 
      case "float32", "float64": 
      case "int", "int16", "int32", "int64", "int8": 
      case "rune", "string": 
      case "uint", "uint16", "uint32", "uint64", "uint8", "uintptr": 
      default: 
       return false 
    } 
    return true 
} 

しかしparse.ParseExprなど

01を使用してそれを行うには良い方法があります
+0

あなたは型宣言をチェックしようとしている、またはソース内の任意の値はいますか? 'ParseExpr'は、式に型情報がないため、実際の型を自分自身に与えることはできません。あなたがタイプを決定する必要がある場所の例を示したなら、おそらく役に立ちます。また、それを呼び出す際の「カスタムタイプ」には、ここにその基本タイプとしてリストされているタイプのいずれかが含まれている場合があります。 – JimB

+0

@JimB構造体フィールドは 'field name'、' field type'と 'struct tag'の3つの部分を持っています。' field type'をチェックする必要があります。 'custom type'に組み込み型。 ネストされたチェックの構造体にValidate関数を生成するコードを書いているので、 'validater'を実装しているフィールドでValidateを呼び出す必要がありますf –

+0

より良い方法は、ソースを解析した後、この場合は 'Validate()error'のように見えるものを呼びたいと思っています。次に、いくつかの構造体の検証コードを生成し、フィールドの型を検査するときに、呼び出しを生成するメソッドを実装する収集された型のセットに、指定された型が含まれているかどうかを確認します。 – mkopriva

答えて

1

信頼性の高い結果を得るには、go/typesパッケージを使用してGoのタイプチェッカーを使用する必要があります。使用するのは簡単ではありませんが、役に立つ入門記事はhttps://golang.org/s/types-tutorialです。

私は一緒にサンプルプログラムを投げたので、何を期待するか分かります。重要なビットはisBasic関数で、残りは実行可能にするための単なる定型文です。特に、ASTのトラバーサルは、特定のサンプルソースコードに対してハードコードされています。私はあなたのために既に自分のコードを用意していると思います。

重要な点は、types.Info構造には、独自のロジックを実装するために必要なすべてのタイプ情報が含まれていることです。

コード生成および/または解析(完全な型情報のために必要な種類のローダーパッケージ)を扱う場合、github.com/fatih/astrewriteおよびgolang.org/x/tools/go/loaderが役に立ちました。

https://play.golang.org/p/A9hdPy-Oy-

package main 

import (
    "bufio" 
    "fmt" 
    "go/ast" 
    "go/parser" 
    "go/token" 
    "go/types" 
    "log" 
    "strings" 
) 

var src = strings.TrimSpace(` 
package main 

type T struct{} 

func f() { 
    var _ T 
    var _ *T 

    var _ int 
    var _ *int 
    var _ **int 
    var _ []int 
    var _ []T 
    var _ map[string]int 
    var _ map[string]T 
} 
`) 

func main() { 
    // Parse source 
    fset := token.NewFileSet() 
    f, err := parser.ParseFile(fset, "src.go", src, 0) 
    if err != nil { 
      log.Fatal(err) 
    } 

    // Run type checker 
    info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} 

    _, err = (&types.Config{}).Check("mypkg", fset, []*ast.File{f}, &info) 
    if err != nil { 
      log.Fatal(err) 
    } 

    printSrc() 

    // Inspect variable types in f() 
    for _, varDecl := range f.Decls[1].(*ast.FuncDecl).Body.List { 
      value := varDecl.(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec) 

      pos := fset.Position(value.Type.Pos()) 
      typ := info.Types[value.Type].Type 

      fmt.Println(pos, "basic:", isBasic(typ)) 
    } 
} 

func isBasic(t types.Type) bool { 
    switch x := t.(type) { 
    case *types.Basic: 
      return true 
    case *types.Slice: 
      return true 
    case *types.Map: 
      return true 
    case *types.Pointer: 
      return isBasic(x.Elem()) 
    default: 
      return false 
    } 
} 

func printSrc() { 
    s := bufio.NewScanner(strings.NewReader(src)) 
    for i := 1; s.Scan(); i++ { 
      fmt.Printf("%2d: %s\n", i, s.Text()) 
    } 
    fmt.Println("") 
} 
関連する問題