...

Source file src/pkg/cmd/fix/typecheck.go

     1	// Copyright 2011 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package main
     6	
     7	import (
     8		"fmt"
     9		"go/ast"
    10		"go/parser"
    11		"go/token"
    12		"io/ioutil"
    13		"os"
    14		"os/exec"
    15		"path/filepath"
    16		"reflect"
    17		"runtime"
    18		"strings"
    19	)
    20	
    21	// Partial type checker.
    22	//
    23	// The fact that it is partial is very important: the input is
    24	// an AST and a description of some type information to
    25	// assume about one or more packages, but not all the
    26	// packages that the program imports. The checker is
    27	// expected to do as much as it can with what it has been
    28	// given. There is not enough information supplied to do
    29	// a full type check, but the type checker is expected to
    30	// apply information that can be derived from variable
    31	// declarations, function and method returns, and type switches
    32	// as far as it can, so that the caller can still tell the types
    33	// of expression relevant to a particular fix.
    34	//
    35	// TODO(rsc,gri): Replace with go/typechecker.
    36	// Doing that could be an interesting test case for go/typechecker:
    37	// the constraints about working with partial information will
    38	// likely exercise it in interesting ways. The ideal interface would
    39	// be to pass typecheck a map from importpath to package API text
    40	// (Go source code), but for now we use data structures (TypeConfig, Type).
    41	//
    42	// The strings mostly use gofmt form.
    43	//
    44	// A Field or FieldList has as its type a comma-separated list
    45	// of the types of the fields. For example, the field list
    46	//	x, y, z int
    47	// has type "int, int, int".
    48	
    49	// The prefix "type " is the type of a type.
    50	// For example, given
    51	//	var x int
    52	//	type T int
    53	// x's type is "int" but T's type is "type int".
    54	// mkType inserts the "type " prefix.
    55	// getType removes it.
    56	// isType tests for it.
    57	
    58	func mkType(t string) string {
    59		return "type " + t
    60	}
    61	
    62	func getType(t string) string {
    63		if !isType(t) {
    64			return ""
    65		}
    66		return t[len("type "):]
    67	}
    68	
    69	func isType(t string) bool {
    70		return strings.HasPrefix(t, "type ")
    71	}
    72	
    73	// TypeConfig describes the universe of relevant types.
    74	// For ease of creation, the types are all referred to by string
    75	// name (e.g., "reflect.Value").  TypeByName is the only place
    76	// where the strings are resolved.
    77	
    78	type TypeConfig struct {
    79		Type map[string]*Type
    80		Var  map[string]string
    81		Func map[string]string
    82	
    83		// External maps from a name to its type.
    84		// It provides additional typings not present in the Go source itself.
    85		// For now, the only additional typings are those generated by cgo.
    86		External map[string]string
    87	}
    88	
    89	// typeof returns the type of the given name, which may be of
    90	// the form "x" or "p.X".
    91	func (cfg *TypeConfig) typeof(name string) string {
    92		if cfg.Var != nil {
    93			if t := cfg.Var[name]; t != "" {
    94				return t
    95			}
    96		}
    97		if cfg.Func != nil {
    98			if t := cfg.Func[name]; t != "" {
    99				return "func()" + t
   100			}
   101		}
   102		return ""
   103	}
   104	
   105	// Type describes the Fields and Methods of a type.
   106	// If the field or method cannot be found there, it is next
   107	// looked for in the Embed list.
   108	type Type struct {
   109		Field  map[string]string // map field name to type
   110		Method map[string]string // map method name to comma-separated return types (should start with "func ")
   111		Embed  []string          // list of types this type embeds (for extra methods)
   112		Def    string            // definition of named type
   113	}
   114	
   115	// dot returns the type of "typ.name", making its decision
   116	// using the type information in cfg.
   117	func (typ *Type) dot(cfg *TypeConfig, name string) string {
   118		if typ.Field != nil {
   119			if t := typ.Field[name]; t != "" {
   120				return t
   121			}
   122		}
   123		if typ.Method != nil {
   124			if t := typ.Method[name]; t != "" {
   125				return t
   126			}
   127		}
   128	
   129		for _, e := range typ.Embed {
   130			etyp := cfg.Type[e]
   131			if etyp != nil {
   132				if t := etyp.dot(cfg, name); t != "" {
   133					return t
   134				}
   135			}
   136		}
   137	
   138		return ""
   139	}
   140	
   141	// typecheck type checks the AST f assuming the information in cfg.
   142	// It returns two maps with type information:
   143	// typeof maps AST nodes to type information in gofmt string form.
   144	// assign maps type strings to lists of expressions that were assigned
   145	// to values of another type that were assigned to that type.
   146	func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) {
   147		typeof = make(map[interface{}]string)
   148		assign = make(map[string][]interface{})
   149		cfg1 := &TypeConfig{}
   150		*cfg1 = *cfg // make copy so we can add locally
   151		copied := false
   152	
   153		// If we import "C", add types of cgo objects.
   154		cfg.External = map[string]string{}
   155		cfg1.External = cfg.External
   156		if imports(f, "C") {
   157			// Run cgo on gofmtFile(f)
   158			// Parse, extract decls from _cgo_gotypes.go
   159			// Map _Ctype_* types to C.* types.
   160			err := func() error {
   161				txt, err := gofmtFile(f)
   162				if err != nil {
   163					return err
   164				}
   165				dir, err := ioutil.TempDir(os.TempDir(), "fix_cgo_typecheck")
   166				if err != nil {
   167					return err
   168				}
   169				defer os.RemoveAll(dir)
   170				err = ioutil.WriteFile(filepath.Join(dir, "in.go"), txt, 0600)
   171				if err != nil {
   172					return err
   173				}
   174				cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "tool", "cgo", "-objdir", dir, "-srcdir", dir, "in.go")
   175				err = cmd.Run()
   176				if err != nil {
   177					return err
   178				}
   179				out, err := ioutil.ReadFile(filepath.Join(dir, "_cgo_gotypes.go"))
   180				if err != nil {
   181					return err
   182				}
   183				cgo, err := parser.ParseFile(token.NewFileSet(), "cgo.go", out, 0)
   184				if err != nil {
   185					return err
   186				}
   187				for _, decl := range cgo.Decls {
   188					fn, ok := decl.(*ast.FuncDecl)
   189					if !ok {
   190						continue
   191					}
   192					if strings.HasPrefix(fn.Name.Name, "_Cfunc_") {
   193						var params, results []string
   194						for _, p := range fn.Type.Params.List {
   195							t := gofmt(p.Type)
   196							t = strings.ReplaceAll(t, "_Ctype_", "C.")
   197							params = append(params, t)
   198						}
   199						for _, r := range fn.Type.Results.List {
   200							t := gofmt(r.Type)
   201							t = strings.ReplaceAll(t, "_Ctype_", "C.")
   202							results = append(results, t)
   203						}
   204						cfg.External["C."+fn.Name.Name[7:]] = joinFunc(params, results)
   205					}
   206				}
   207				return nil
   208			}()
   209			if err != nil {
   210				fmt.Printf("warning: no cgo types: %s\n", err)
   211			}
   212		}
   213	
   214		// gather function declarations
   215		for _, decl := range f.Decls {
   216			fn, ok := decl.(*ast.FuncDecl)
   217			if !ok {
   218				continue
   219			}
   220			typecheck1(cfg, fn.Type, typeof, assign)
   221			t := typeof[fn.Type]
   222			if fn.Recv != nil {
   223				// The receiver must be a type.
   224				rcvr := typeof[fn.Recv]
   225				if !isType(rcvr) {
   226					if len(fn.Recv.List) != 1 {
   227						continue
   228					}
   229					rcvr = mkType(gofmt(fn.Recv.List[0].Type))
   230					typeof[fn.Recv.List[0].Type] = rcvr
   231				}
   232				rcvr = getType(rcvr)
   233				if rcvr != "" && rcvr[0] == '*' {
   234					rcvr = rcvr[1:]
   235				}
   236				typeof[rcvr+"."+fn.Name.Name] = t
   237			} else {
   238				if isType(t) {
   239					t = getType(t)
   240				} else {
   241					t = gofmt(fn.Type)
   242				}
   243				typeof[fn.Name] = t
   244	
   245				// Record typeof[fn.Name.Obj] for future references to fn.Name.
   246				typeof[fn.Name.Obj] = t
   247			}
   248		}
   249	
   250		// gather struct declarations
   251		for _, decl := range f.Decls {
   252			d, ok := decl.(*ast.GenDecl)
   253			if ok {
   254				for _, s := range d.Specs {
   255					switch s := s.(type) {
   256					case *ast.TypeSpec:
   257						if cfg1.Type[s.Name.Name] != nil {
   258							break
   259						}
   260						if !copied {
   261							copied = true
   262							// Copy map lazily: it's time.
   263							cfg1.Type = make(map[string]*Type)
   264							for k, v := range cfg.Type {
   265								cfg1.Type[k] = v
   266							}
   267						}
   268						t := &Type{Field: map[string]string{}}
   269						cfg1.Type[s.Name.Name] = t
   270						switch st := s.Type.(type) {
   271						case *ast.StructType:
   272							for _, f := range st.Fields.List {
   273								for _, n := range f.Names {
   274									t.Field[n.Name] = gofmt(f.Type)
   275								}
   276							}
   277						case *ast.ArrayType, *ast.StarExpr, *ast.MapType:
   278							t.Def = gofmt(st)
   279						}
   280					}
   281				}
   282			}
   283		}
   284	
   285		typecheck1(cfg1, f, typeof, assign)
   286		return typeof, assign
   287	}
   288	
   289	func makeExprList(a []*ast.Ident) []ast.Expr {
   290		var b []ast.Expr
   291		for _, x := range a {
   292			b = append(b, x)
   293		}
   294		return b
   295	}
   296	
   297	// Typecheck1 is the recursive form of typecheck.
   298	// It is like typecheck but adds to the information in typeof
   299	// instead of allocating a new map.
   300	func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, assign map[string][]interface{}) {
   301		// set sets the type of n to typ.
   302		// If isDecl is true, n is being declared.
   303		set := func(n ast.Expr, typ string, isDecl bool) {
   304			if typeof[n] != "" || typ == "" {
   305				if typeof[n] != typ {
   306					assign[typ] = append(assign[typ], n)
   307				}
   308				return
   309			}
   310			typeof[n] = typ
   311	
   312			// If we obtained typ from the declaration of x
   313			// propagate the type to all the uses.
   314			// The !isDecl case is a cheat here, but it makes
   315			// up in some cases for not paying attention to
   316			// struct fields. The real type checker will be
   317			// more accurate so we won't need the cheat.
   318			if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") {
   319				typeof[id.Obj] = typ
   320			}
   321		}
   322	
   323		// Type-check an assignment lhs = rhs.
   324		// If isDecl is true, this is := so we can update
   325		// the types of the objects that lhs refers to.
   326		typecheckAssign := func(lhs, rhs []ast.Expr, isDecl bool) {
   327			if len(lhs) > 1 && len(rhs) == 1 {
   328				if _, ok := rhs[0].(*ast.CallExpr); ok {
   329					t := split(typeof[rhs[0]])
   330					// Lists should have same length but may not; pair what can be paired.
   331					for i := 0; i < len(lhs) && i < len(t); i++ {
   332						set(lhs[i], t[i], isDecl)
   333					}
   334					return
   335				}
   336			}
   337			if len(lhs) == 1 && len(rhs) == 2 {
   338				// x = y, ok
   339				rhs = rhs[:1]
   340			} else if len(lhs) == 2 && len(rhs) == 1 {
   341				// x, ok = y
   342				lhs = lhs[:1]
   343			}
   344	
   345			// Match as much as we can.
   346			for i := 0; i < len(lhs) && i < len(rhs); i++ {
   347				x, y := lhs[i], rhs[i]
   348				if typeof[y] != "" {
   349					set(x, typeof[y], isDecl)
   350				} else {
   351					set(y, typeof[x], false)
   352				}
   353			}
   354		}
   355	
   356		expand := func(s string) string {
   357			typ := cfg.Type[s]
   358			if typ != nil && typ.Def != "" {
   359				return typ.Def
   360			}
   361			return s
   362		}
   363	
   364		// The main type check is a recursive algorithm implemented
   365		// by walkBeforeAfter(n, before, after).
   366		// Most of it is bottom-up, but in a few places we need
   367		// to know the type of the function we are checking.
   368		// The before function records that information on
   369		// the curfn stack.
   370		var curfn []*ast.FuncType
   371	
   372		before := func(n interface{}) {
   373			// push function type on stack
   374			switch n := n.(type) {
   375			case *ast.FuncDecl:
   376				curfn = append(curfn, n.Type)
   377			case *ast.FuncLit:
   378				curfn = append(curfn, n.Type)
   379			}
   380		}
   381	
   382		// After is the real type checker.
   383		after := func(n interface{}) {
   384			if n == nil {
   385				return
   386			}
   387			if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace
   388				defer func() {
   389					if t := typeof[n]; t != "" {
   390						pos := fset.Position(n.(ast.Node).Pos())
   391						fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos, gofmt(n), t)
   392					}
   393				}()
   394			}
   395	
   396			switch n := n.(type) {
   397			case *ast.FuncDecl, *ast.FuncLit:
   398				// pop function type off stack
   399				curfn = curfn[:len(curfn)-1]
   400	
   401			case *ast.FuncType:
   402				typeof[n] = mkType(joinFunc(split(typeof[n.Params]), split(typeof[n.Results])))
   403	
   404			case *ast.FieldList:
   405				// Field list is concatenation of sub-lists.
   406				t := ""
   407				for _, field := range n.List {
   408					if t != "" {
   409						t += ", "
   410					}
   411					t += typeof[field]
   412				}
   413				typeof[n] = t
   414	
   415			case *ast.Field:
   416				// Field is one instance of the type per name.
   417				all := ""
   418				t := typeof[n.Type]
   419				if !isType(t) {
   420					// Create a type, because it is typically *T or *p.T
   421					// and we might care about that type.
   422					t = mkType(gofmt(n.Type))
   423					typeof[n.Type] = t
   424				}
   425				t = getType(t)
   426				if len(n.Names) == 0 {
   427					all = t
   428				} else {
   429					for _, id := range n.Names {
   430						if all != "" {
   431							all += ", "
   432						}
   433						all += t
   434						typeof[id.Obj] = t
   435						typeof[id] = t
   436					}
   437				}
   438				typeof[n] = all
   439	
   440			case *ast.ValueSpec:
   441				// var declaration. Use type if present.
   442				if n.Type != nil {
   443					t := typeof[n.Type]
   444					if !isType(t) {
   445						t = mkType(gofmt(n.Type))
   446						typeof[n.Type] = t
   447					}
   448					t = getType(t)
   449					for _, id := range n.Names {
   450						set(id, t, true)
   451					}
   452				}
   453				// Now treat same as assignment.
   454				typecheckAssign(makeExprList(n.Names), n.Values, true)
   455	
   456			case *ast.AssignStmt:
   457				typecheckAssign(n.Lhs, n.Rhs, n.Tok == token.DEFINE)
   458	
   459			case *ast.Ident:
   460				// Identifier can take its type from underlying object.
   461				if t := typeof[n.Obj]; t != "" {
   462					typeof[n] = t
   463				}
   464	
   465			case *ast.SelectorExpr:
   466				// Field or method.
   467				name := n.Sel.Name
   468				if t := typeof[n.X]; t != "" {
   469					t = strings.TrimPrefix(t, "*") // implicit *
   470					if typ := cfg.Type[t]; typ != nil {
   471						if t := typ.dot(cfg, name); t != "" {
   472							typeof[n] = t
   473							return
   474						}
   475					}
   476					tt := typeof[t+"."+name]
   477					if isType(tt) {
   478						typeof[n] = getType(tt)
   479						return
   480					}
   481				}
   482				// Package selector.
   483				if x, ok := n.X.(*ast.Ident); ok && x.Obj == nil {
   484					str := x.Name + "." + name
   485					if cfg.Type[str] != nil {
   486						typeof[n] = mkType(str)
   487						return
   488					}
   489					if t := cfg.typeof(x.Name + "." + name); t != "" {
   490						typeof[n] = t
   491						return
   492					}
   493				}
   494	
   495			case *ast.CallExpr:
   496				// make(T) has type T.
   497				if isTopName(n.Fun, "make") && len(n.Args) >= 1 {
   498					typeof[n] = gofmt(n.Args[0])
   499					return
   500				}
   501				// new(T) has type *T
   502				if isTopName(n.Fun, "new") && len(n.Args) == 1 {
   503					typeof[n] = "*" + gofmt(n.Args[0])
   504					return
   505				}
   506				// Otherwise, use type of function to determine arguments.
   507				t := typeof[n.Fun]
   508				if t == "" {
   509					t = cfg.External[gofmt(n.Fun)]
   510				}
   511				in, out := splitFunc(t)
   512				if in == nil && out == nil {
   513					return
   514				}
   515				typeof[n] = join(out)
   516				for i, arg := range n.Args {
   517					if i >= len(in) {
   518						break
   519					}
   520					if typeof[arg] == "" {
   521						typeof[arg] = in[i]
   522					}
   523				}
   524	
   525			case *ast.TypeAssertExpr:
   526				// x.(type) has type of x.
   527				if n.Type == nil {
   528					typeof[n] = typeof[n.X]
   529					return
   530				}
   531				// x.(T) has type T.
   532				if t := typeof[n.Type]; isType(t) {
   533					typeof[n] = getType(t)
   534				} else {
   535					typeof[n] = gofmt(n.Type)
   536				}
   537	
   538			case *ast.SliceExpr:
   539				// x[i:j] has type of x.
   540				typeof[n] = typeof[n.X]
   541	
   542			case *ast.IndexExpr:
   543				// x[i] has key type of x's type.
   544				t := expand(typeof[n.X])
   545				if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
   546					// Lazy: assume there are no nested [] in the array
   547					// length or map key type.
   548					if i := strings.Index(t, "]"); i >= 0 {
   549						typeof[n] = t[i+1:]
   550					}
   551				}
   552	
   553			case *ast.StarExpr:
   554				// *x for x of type *T has type T when x is an expr.
   555				// We don't use the result when *x is a type, but
   556				// compute it anyway.
   557				t := expand(typeof[n.X])
   558				if isType(t) {
   559					typeof[n] = "type *" + getType(t)
   560				} else if strings.HasPrefix(t, "*") {
   561					typeof[n] = t[len("*"):]
   562				}
   563	
   564			case *ast.UnaryExpr:
   565				// &x for x of type T has type *T.
   566				t := typeof[n.X]
   567				if t != "" && n.Op == token.AND {
   568					typeof[n] = "*" + t
   569				}
   570	
   571			case *ast.CompositeLit:
   572				// T{...} has type T.
   573				typeof[n] = gofmt(n.Type)
   574	
   575				// Propagate types down to values used in the composite literal.
   576				t := expand(typeof[n])
   577				if strings.HasPrefix(t, "[") { // array or slice
   578					// Lazy: assume there are no nested [] in the array length.
   579					if i := strings.Index(t, "]"); i >= 0 {
   580						et := t[i+1:]
   581						for _, e := range n.Elts {
   582							if kv, ok := e.(*ast.KeyValueExpr); ok {
   583								e = kv.Value
   584							}
   585							if typeof[e] == "" {
   586								typeof[e] = et
   587							}
   588						}
   589					}
   590				}
   591				if strings.HasPrefix(t, "map[") { // map
   592					// Lazy: assume there are no nested [] in the map key type.
   593					if i := strings.Index(t, "]"); i >= 0 {
   594						kt, vt := t[4:i], t[i+1:]
   595						for _, e := range n.Elts {
   596							if kv, ok := e.(*ast.KeyValueExpr); ok {
   597								if typeof[kv.Key] == "" {
   598									typeof[kv.Key] = kt
   599								}
   600								if typeof[kv.Value] == "" {
   601									typeof[kv.Value] = vt
   602								}
   603							}
   604						}
   605					}
   606				}
   607				if typ := cfg.Type[t]; typ != nil && len(typ.Field) > 0 { // struct
   608					for _, e := range n.Elts {
   609						if kv, ok := e.(*ast.KeyValueExpr); ok {
   610							if ft := typ.Field[fmt.Sprintf("%s", kv.Key)]; ft != "" {
   611								if typeof[kv.Value] == "" {
   612									typeof[kv.Value] = ft
   613								}
   614							}
   615						}
   616					}
   617				}
   618	
   619			case *ast.ParenExpr:
   620				// (x) has type of x.
   621				typeof[n] = typeof[n.X]
   622	
   623			case *ast.RangeStmt:
   624				t := expand(typeof[n.X])
   625				if t == "" {
   626					return
   627				}
   628				var key, value string
   629				if t == "string" {
   630					key, value = "int", "rune"
   631				} else if strings.HasPrefix(t, "[") {
   632					key = "int"
   633					if i := strings.Index(t, "]"); i >= 0 {
   634						value = t[i+1:]
   635					}
   636				} else if strings.HasPrefix(t, "map[") {
   637					if i := strings.Index(t, "]"); i >= 0 {
   638						key, value = t[4:i], t[i+1:]
   639					}
   640				}
   641				changed := false
   642				if n.Key != nil && key != "" {
   643					changed = true
   644					set(n.Key, key, n.Tok == token.DEFINE)
   645				}
   646				if n.Value != nil && value != "" {
   647					changed = true
   648					set(n.Value, value, n.Tok == token.DEFINE)
   649				}
   650				// Ugly failure of vision: already type-checked body.
   651				// Do it again now that we have that type info.
   652				if changed {
   653					typecheck1(cfg, n.Body, typeof, assign)
   654				}
   655	
   656			case *ast.TypeSwitchStmt:
   657				// Type of variable changes for each case in type switch,
   658				// but go/parser generates just one variable.
   659				// Repeat type check for each case with more precise
   660				// type information.
   661				as, ok := n.Assign.(*ast.AssignStmt)
   662				if !ok {
   663					return
   664				}
   665				varx, ok := as.Lhs[0].(*ast.Ident)
   666				if !ok {
   667					return
   668				}
   669				t := typeof[varx]
   670				for _, cas := range n.Body.List {
   671					cas := cas.(*ast.CaseClause)
   672					if len(cas.List) == 1 {
   673						// Variable has specific type only when there is
   674						// exactly one type in the case list.
   675						if tt := typeof[cas.List[0]]; isType(tt) {
   676							tt = getType(tt)
   677							typeof[varx] = tt
   678							typeof[varx.Obj] = tt
   679							typecheck1(cfg, cas.Body, typeof, assign)
   680						}
   681					}
   682				}
   683				// Restore t.
   684				typeof[varx] = t
   685				typeof[varx.Obj] = t
   686	
   687			case *ast.ReturnStmt:
   688				if len(curfn) == 0 {
   689					// Probably can't happen.
   690					return
   691				}
   692				f := curfn[len(curfn)-1]
   693				res := n.Results
   694				if f.Results != nil {
   695					t := split(typeof[f.Results])
   696					for i := 0; i < len(res) && i < len(t); i++ {
   697						set(res[i], t[i], false)
   698					}
   699				}
   700	
   701			case *ast.BinaryExpr:
   702				// Propagate types across binary ops that require two args of the same type.
   703				switch n.Op {
   704				case token.EQL, token.NEQ: // TODO: more cases. This is enough for the cftype fix.
   705					if typeof[n.X] != "" && typeof[n.Y] == "" {
   706						typeof[n.Y] = typeof[n.X]
   707					}
   708					if typeof[n.X] == "" && typeof[n.Y] != "" {
   709						typeof[n.X] = typeof[n.Y]
   710					}
   711				}
   712			}
   713		}
   714		walkBeforeAfter(f, before, after)
   715	}
   716	
   717	// Convert between function type strings and lists of types.
   718	// Using strings makes this a little harder, but it makes
   719	// a lot of the rest of the code easier. This will all go away
   720	// when we can use go/typechecker directly.
   721	
   722	// splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"].
   723	func splitFunc(s string) (in, out []string) {
   724		if !strings.HasPrefix(s, "func(") {
   725			return nil, nil
   726		}
   727	
   728		i := len("func(") // index of beginning of 'in' arguments
   729		nparen := 0
   730		for j := i; j < len(s); j++ {
   731			switch s[j] {
   732			case '(':
   733				nparen++
   734			case ')':
   735				nparen--
   736				if nparen < 0 {
   737					// found end of parameter list
   738					out := strings.TrimSpace(s[j+1:])
   739					if len(out) >= 2 && out[0] == '(' && out[len(out)-1] == ')' {
   740						out = out[1 : len(out)-1]
   741					}
   742					return split(s[i:j]), split(out)
   743				}
   744			}
   745		}
   746		return nil, nil
   747	}
   748	
   749	// joinFunc is the inverse of splitFunc.
   750	func joinFunc(in, out []string) string {
   751		outs := ""
   752		if len(out) == 1 {
   753			outs = " " + out[0]
   754		} else if len(out) > 1 {
   755			outs = " (" + join(out) + ")"
   756		}
   757		return "func(" + join(in) + ")" + outs
   758	}
   759	
   760	// split splits "int, float" into ["int", "float"] and splits "" into [].
   761	func split(s string) []string {
   762		out := []string{}
   763		i := 0 // current type being scanned is s[i:j].
   764		nparen := 0
   765		for j := 0; j < len(s); j++ {
   766			switch s[j] {
   767			case ' ':
   768				if i == j {
   769					i++
   770				}
   771			case '(':
   772				nparen++
   773			case ')':
   774				nparen--
   775				if nparen < 0 {
   776					// probably can't happen
   777					return nil
   778				}
   779			case ',':
   780				if nparen == 0 {
   781					if i < j {
   782						out = append(out, s[i:j])
   783					}
   784					i = j + 1
   785				}
   786			}
   787		}
   788		if nparen != 0 {
   789			// probably can't happen
   790			return nil
   791		}
   792		if i < len(s) {
   793			out = append(out, s[i:])
   794		}
   795		return out
   796	}
   797	
   798	// join is the inverse of split.
   799	func join(x []string) string {
   800		return strings.Join(x, ", ")
   801	}
   802	

View as plain text