2017-09-28 14 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'의 세 부분으로 구성됩니다.'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/astrewritegolang.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("") 
}