gorgonia.org/gorgonia@v0.9.17/cmd/genapi/generatemonads.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/ast"
     7  	"go/parser"
     8  	"go/token"
     9  	"log"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  )
    14  
    15  type nametypePair struct {
    16  	name string
    17  	*ast.FuncType
    18  }
    19  
    20  func functions(decls []ast.Decl) (signatures []nametypePair) {
    21  	for _, decl := range decls {
    22  		switch d := decl.(type) {
    23  		case *ast.FuncDecl:
    24  			signatures = append(signatures, nametypePair{d.Name.Name, d.Type})
    25  		default:
    26  		}
    27  	}
    28  	return
    29  }
    30  
    31  type strRepr struct {
    32  	name     string
    33  	inTypes  []string
    34  	retTypes []string
    35  
    36  	printName bool
    37  }
    38  
    39  func (s strRepr) String() string {
    40  	buf := new(bytes.Buffer)
    41  	buf.Write([]byte("func "))
    42  	if s.printName {
    43  		buf.Write([]byte(s.name))
    44  	}
    45  
    46  	buf.Write([]byte("("))
    47  	for i, v := range s.inTypes {
    48  		buf.Write([]byte(v))
    49  		if i < len(s.inTypes)-1 {
    50  			buf.Write([]byte(", "))
    51  		}
    52  	}
    53  	buf.Write([]byte(") ("))
    54  	for i, v := range s.retTypes {
    55  		buf.Write([]byte(v))
    56  		if i < len(s.retTypes)-1 {
    57  			buf.Write([]byte(", "))
    58  		}
    59  	}
    60  	buf.Write([]byte(")"))
    61  	return buf.String()
    62  }
    63  
    64  func processSig(pair nametypePair) strRepr {
    65  	a := pair.FuncType
    66  	var inTypes, retTypes []string
    67  	if a.Params == nil {
    68  		goto next
    69  	}
    70  	for _, field := range a.Params.List {
    71  		names := len(field.Names)
    72  		typ := parseTypeExpr(field.Type)
    73  		if names == 0 {
    74  			inTypes = append(inTypes, typ)
    75  			continue
    76  		}
    77  		for i := 0; i < names; i++ {
    78  			inTypes = append(inTypes, typ)
    79  		}
    80  	}
    81  next:
    82  	if a.Results == nil {
    83  		return strRepr{pair.name, inTypes, retTypes, true}
    84  	}
    85  	for _, field := range a.Results.List {
    86  		names := len(field.Names)
    87  		typ := parseTypeExpr(field.Type)
    88  		if names == 0 {
    89  			retTypes = append(retTypes, typ)
    90  			continue
    91  		}
    92  		for i := 0; i < names; i++ {
    93  			retTypes = append(retTypes, typ)
    94  		}
    95  	}
    96  	return strRepr{pair.name, inTypes, retTypes, true}
    97  }
    98  
    99  func parseTypeExpr(expr ast.Expr) string {
   100  	switch e := expr.(type) {
   101  	case *ast.Ident:
   102  		return e.Name
   103  	case *ast.StarExpr:
   104  		x := parseTypeExpr(e.X)
   105  		return "*" + x
   106  	case *ast.SelectorExpr:
   107  		return parseTypeExpr(e.X) + "." + e.Sel.Name
   108  	case *ast.Ellipsis:
   109  		return "..." + parseTypeExpr(e.Elt)
   110  	case *ast.ArrayType:
   111  		return "[]" + parseTypeExpr(e.Elt)
   112  	default:
   113  		return fmt.Sprintf("%T", expr)
   114  	}
   115  }
   116  
   117  func filterSigs(xs []strRepr, fn func(strRepr) bool) (retVal []strRepr) {
   118  	for _, x := range xs {
   119  		if fn(x) {
   120  			retVal = append(retVal, x)
   121  		}
   122  	}
   123  	return
   124  }
   125  
   126  func functionSignatures() {
   127  	files := path.Join(gorgonialoc, "*.go")
   128  	matches, err := filepath.Glob(files)
   129  
   130  	if err != nil {
   131  		log.Fatal(err)
   132  	}
   133  	fset := token.NewFileSet()
   134  
   135  	var allFns []strRepr
   136  	for _, f := range matches {
   137  		file, err := parser.ParseFile(fset, f, nil, parser.AllErrors)
   138  		if err != nil {
   139  			log.Fatal(err)
   140  
   141  		}
   142  
   143  		fns := functions(file.Decls)
   144  		for _, fn := range fns {
   145  			sig := processSig(fn)
   146  			sig.printName = false
   147  			if strings.Title(sig.name) == sig.name {
   148  				allFns = append(allFns, sig)
   149  			}
   150  		}
   151  	}
   152  	f := func(a strRepr) bool {
   153  		want := []string{"Nodes", "error"}
   154  		if len(a.retTypes) != len(want) {
   155  			return false
   156  		}
   157  		for i, v := range a.retTypes {
   158  			if v != want[i] {
   159  				return false
   160  			}
   161  		}
   162  		return true
   163  	}
   164  
   165  	signatures := make(map[string]int)
   166  	interesting := filterSigs(allFns, f)
   167  	for _, v := range interesting {
   168  		v.printName = true
   169  		signatures[fmt.Sprintf("%v", v)]++
   170  	}
   171  
   172  	for k, v := range signatures {
   173  		fmt.Printf("%v\t%d\n", k, v)
   174  	}
   175  }