bou.ke/statictemplate@v0.0.0-20180821122055-510411a5e7dd/statictemplate/translate.go (about)

     1  package statictemplate
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/format"
     7  	"go/types"
     8  	"io"
     9  	"path"
    10  	"text/template/parse"
    11  
    12  	"bou.ke/statictemplate/internal"
    13  	"golang.org/x/tools/go/types/typeutil"
    14  )
    15  
    16  var builtinFuncs map[string]*types.Func
    17  
    18  func init() {
    19  	var err error
    20  	_, _, builtinFuncs, err = internal.ImportFuncMap("bou.ke/statictemplate/funcs.Funcs")
    21  	if err != nil {
    22  		panic(err)
    23  	}
    24  }
    25  
    26  const varPrefix = "_Var"
    27  
    28  type scope map[string]types.Type
    29  
    30  // TranslateInstruction specifies a single function to be generated from a template
    31  type TranslateInstruction struct {
    32  	FunctionName string
    33  	TemplateName string
    34  	Dot          types.Type
    35  }
    36  
    37  // Translate is a convenience method for New(template).Translate(pkg, instructions)
    38  func Translate(template interface{}, pkg string, instructions []TranslateInstruction) ([]byte, error) {
    39  	translator := New(template)
    40  	return translator.Translate(pkg, instructions)
    41  }
    42  
    43  // Translator converts a template with a set of instructions to Go code
    44  type Translator struct {
    45  	Funcs map[string]*types.Func
    46  
    47  	scopes               []scope
    48  	template             wrappedTemplate
    49  	id                   int
    50  	specializedFunctions map[wrappedTemplate]*typeutil.Map
    51  	errorFunctions       *typeutil.Map
    52  	generatedFunctions   []string
    53  	imports              map[string]string
    54  }
    55  
    56  // New creates a new instance of Translator
    57  func New(template interface{}) *Translator {
    58  	wrapped := wrap(template)
    59  	return &Translator{
    60  		Funcs: map[string]*types.Func{},
    61  
    62  		scopes: []scope{
    63  			make(scope),
    64  		},
    65  		specializedFunctions: make(map[wrappedTemplate]*typeutil.Map),
    66  		errorFunctions:       &typeutil.Map{},
    67  		imports:              make(map[string]string),
    68  		template:             wrapped,
    69  	}
    70  }
    71  
    72  // Translate converts a template with a set of instructions to Go code
    73  func (t *Translator) Translate(pkg string, instructions []TranslateInstruction) ([]byte, error) {
    74  	var result []resultEntry
    75  
    76  	for _, instruction := range instructions {
    77  		temp, err := t.template.Lookup(instruction.TemplateName)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		functionName, err := t.generateTemplate(temp, instruction.Dot)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		result = append(result, resultEntry{
    86  			name:         instruction.FunctionName,
    87  			typeName:     t.typeName(instruction.Dot),
    88  			functionName: functionName,
    89  		})
    90  	}
    91  
    92  	t.importPackage("io")
    93  
    94  	var buf bytes.Buffer
    95  
    96  	fmt.Fprintf(&buf, `package %s
    97  import (
    98  `, pkg)
    99  	for pkgPath, alias := range t.imports {
   100  		if path.Base(pkgPath) == alias {
   101  			fmt.Fprintf(&buf, "%q\n", pkgPath)
   102  		} else {
   103  			fmt.Fprintf(&buf, "%s %q\n", alias, pkgPath)
   104  		}
   105  	}
   106  	io.WriteString(&buf, ")")
   107  
   108  	for _, entry := range result {
   109  		fmt.Fprintf(&buf, `
   110  func %s(w io.Writer, dot %s) (err error) {
   111  	defer func() {
   112  		if recovered := recover(); recovered != nil {
   113  			var ok bool
   114  			if err, ok = recovered.(error); !ok {
   115  				panic(recovered)
   116  			}
   117  		}
   118  	}()
   119  	return %s(w, dot)
   120  }
   121  `, entry.name, entry.typeName, entry.functionName)
   122  	}
   123  
   124  	for _, code := range t.generatedFunctions {
   125  		io.WriteString(&buf, "\n")
   126  		io.WriteString(&buf, code)
   127  	}
   128  
   129  	formatted, err := format.Source(buf.Bytes())
   130  	if err != nil {
   131  		return nil, fmt.Errorf("%s: %v", buf.String(), err)
   132  	}
   133  	return formatted, nil
   134  }
   135  
   136  func (t *Translator) importPackage(name string) string {
   137  	if pkg, ok := t.imports[name]; ok {
   138  		return pkg
   139  	}
   140  
   141  	var pkg string
   142  	switch name {
   143  	case "fmt", "io":
   144  		pkg = name
   145  	case "text/template":
   146  		pkg = "template"
   147  	case "bou.ke/statictemplate/funcs":
   148  		pkg = "funcs"
   149  	default:
   150  		pkg = fmt.Sprintf("pkg%d", t.id)
   151  		t.id++
   152  	}
   153  
   154  	t.imports[name] = pkg
   155  	return pkg
   156  }
   157  
   158  func (t *Translator) generateFunctionName() string {
   159  	name := fmt.Sprintf("fun%d", t.id)
   160  	t.id++
   161  	return name
   162  }
   163  
   164  func (t *Translator) pushScope() {
   165  	t.scopes = append(t.scopes, make(scope))
   166  }
   167  
   168  func (t *Translator) popScope() {
   169  	t.scopes = t.scopes[:len(t.scopes)-1]
   170  }
   171  
   172  // Checks whether identifier is in scope
   173  func (t *Translator) inScope(name string) bool {
   174  	_, ok := t.scopes[len(t.scopes)-1][name]
   175  	return ok
   176  }
   177  
   178  // Checks whether identifier is in scope, or add it otherwise
   179  func (t *Translator) addToScope(name string, typ types.Type) {
   180  	t.scopes[len(t.scopes)-1][name] = typ
   181  }
   182  
   183  func (t *Translator) findVariable(name string) (types.Type, error) {
   184  	for i := len(t.scopes) - 1; i >= 0; i-- {
   185  		if typ, ok := t.scopes[i][name]; ok {
   186  			return typ, nil
   187  		}
   188  	}
   189  	return nil, fmt.Errorf("can't find variable %s in scope", name)
   190  }
   191  
   192  type sortedTypes []types.Type
   193  
   194  func (a sortedTypes) Len() int      { return len(a) }
   195  func (a sortedTypes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   196  func (a sortedTypes) Less(i, j int) bool {
   197  	if a[i] == nil {
   198  		return true
   199  	} else if a[j] == nil {
   200  		return false
   201  	} else {
   202  		return a[i].String() < a[j].String()
   203  	}
   204  }
   205  
   206  type resultEntry struct {
   207  	name, typeName, functionName string
   208  }
   209  
   210  func (t *Translator) translateNode(w io.Writer, node parse.Node, dot types.Type) error {
   211  	switch node := node.(type) {
   212  	case *parse.ActionNode:
   213  		pipe := node.Pipe
   214  		writer := w
   215  		if len(pipe.Decl) == 0 {
   216  			writer = new(bytes.Buffer)
   217  		} else if len(pipe.Decl) == 1 {
   218  			ident := pipe.Decl[0].Ident[0][1:]
   219  			if t.inScope(ident) {
   220  				fmt.Fprintf(writer, "%s%s = ", varPrefix, ident)
   221  			} else {
   222  				fmt.Fprintf(writer, "%s%s := ", varPrefix, ident)
   223  			}
   224  		} else {
   225  			return fmt.Errorf("only support single variable for assignment")
   226  		}
   227  
   228  		typ, err := t.translatePipe(writer, dot, pipe)
   229  		if err != nil {
   230  			return err
   231  		}
   232  		if len(pipe.Decl) == 1 {
   233  			ident := pipe.Decl[0].Ident[0][1:]
   234  			if !t.inScope(ident) {
   235  				fmt.Fprintf(writer, "\n_ = %s%s", varPrefix, ident)
   236  			}
   237  			t.addToScope(ident, typ)
   238  		}
   239  
   240  		if len(node.Pipe.Decl) == 0 {
   241  			basic, ok := typ.(*types.Basic)
   242  			if ok && basic.Kind() == types.String {
   243  				t.importPackage("io")
   244  				io.WriteString(w, "_, _ = io.WriteString(w, ")
   245  			} else {
   246  				t.importPackage("fmt")
   247  				io.WriteString(w, "_, _ = fmt.Fprint(w, ")
   248  			}
   249  			writer.(*bytes.Buffer).WriteTo(w)
   250  			io.WriteString(w, ")")
   251  		}
   252  		_, err = io.WriteString(w, "\n")
   253  
   254  		return err
   255  	case *parse.IfNode:
   256  		return t.translateScoped(w, dot, node.Type(), node.Pipe, node.List, node.ElseList)
   257  	case *parse.ListNode:
   258  		for _, item := range node.Nodes {
   259  			if err := t.translateNode(w, item, dot); err != nil {
   260  				return err
   261  			}
   262  		}
   263  		return nil
   264  	case *parse.RangeNode:
   265  		return t.translateScoped(w, dot, node.Type(), node.Pipe, node.List, node.ElseList)
   266  	case *parse.TemplateNode:
   267  		return t.translateTemplate(w, dot, node)
   268  	case *parse.TextNode:
   269  		t.importPackage("io")
   270  		_, err := fmt.Fprintf(w, "_, _ = io.WriteString(w, %q)\n", node.Text)
   271  		return err
   272  	case *parse.WithNode:
   273  		return t.translateScoped(w, dot, node.Type(), node.Pipe, node.List, node.ElseList)
   274  	default:
   275  		return fmt.Errorf("unknown Node %v", node.Type())
   276  	}
   277  }
   278  
   279  func typeIsNil(typ types.Type) bool {
   280  	return typ == nil || types.Identical(typ, types.Typ[types.UntypedNil])
   281  }
   282  
   283  func writeTruthiness(w io.Writer, typ types.Type) error {
   284  	if typeIsNil(typ) {
   285  		_, err := io.WriteString(w, "eval != nil")
   286  		return err
   287  	}
   288  	switch typ := typ.(type) {
   289  	case *types.Array, *types.Map, *types.Slice:
   290  		_, err := io.WriteString(w, "len(eval) != 0")
   291  		return err
   292  	case *types.Basic:
   293  		info := typ.Info()
   294  		if info&types.IsNumeric != 0 {
   295  			_, err := io.WriteString(w, "eval != 0")
   296  			return err
   297  		} else if info&types.IsString != 0 {
   298  			_, err := io.WriteString(w, "len(eval) != 0")
   299  			return err
   300  		} else if info&types.IsBoolean != 0 {
   301  			_, err := io.WriteString(w, "eval")
   302  			return err
   303  		}
   304  		return fmt.Errorf("don't know how to evaluate %s", typ)
   305  	case *types.Pointer, *types.Chan:
   306  		_, err := io.WriteString(w, "eval != nil")
   307  		return err
   308  	case *types.Struct:
   309  		_, err := io.WriteString(w, "true")
   310  		return err
   311  	default:
   312  		return fmt.Errorf("don't know how to evaluate %s", typ)
   313  	}
   314  }
   315  
   316  func (t *Translator) generateTemplate(temp wrappedTemplate, typ types.Type) (string, error) {
   317  	funcs, ok := t.specializedFunctions[temp]
   318  	if !ok {
   319  		funcs = &typeutil.Map{}
   320  		t.specializedFunctions[temp] = funcs
   321  	}
   322  	functionName, ok := funcs.At(typ).(string)
   323  	if !ok {
   324  		functionName = t.generateFunctionName()
   325  		funcs.Set(typ, functionName)
   326  
   327  		var buf bytes.Buffer
   328  		typeName := "interface{}"
   329  		if !typeIsNil(typ) {
   330  			typeName = t.typeName(typ)
   331  		}
   332  
   333  		fmt.Fprintf(&buf, "// %s(", temp.Name())
   334  		if typeIsNil(typ) {
   335  			buf.WriteString("nil")
   336  		} else {
   337  			buf.WriteString(typeName)
   338  		}
   339  		t.importPackage("io")
   340  		fmt.Fprintf(&buf, ")\nfunc %s(w io.Writer, dot %s) error {\n", functionName, typeName)
   341  		oldScopes := t.scopes
   342  		t.scopes = []scope{make(scope)}
   343  		if err := t.translateNode(&buf, temp.Tree().Root, typ); err != nil {
   344  			return "", err
   345  		}
   346  		t.scopes = oldScopes
   347  		buf.WriteString("return nil\n}\n")
   348  
   349  		t.generatedFunctions = append(t.generatedFunctions, buf.String())
   350  	}
   351  
   352  	return functionName, nil
   353  }
   354  
   355  func (t *Translator) translateTemplate(w io.Writer, dot types.Type, node *parse.TemplateNode) error {
   356  	var buf bytes.Buffer
   357  	typ, err := t.translatePipe(&buf, dot, node.Pipe)
   358  	if err != nil {
   359  		return err
   360  	}
   361  	temp, err := t.template.Lookup(node.Name)
   362  	if err != nil {
   363  		return err
   364  	}
   365  	name, err := t.generateTemplate(temp, typ)
   366  	if err != nil {
   367  		return err
   368  	}
   369  
   370  	fmt.Fprintf(w, "if err := %s(w, ", name)
   371  	buf.WriteTo(w)
   372  	_, err = io.WriteString(w, "); err != nil {\nreturn err\n}\n")
   373  	return err
   374  }
   375  
   376  func (t *Translator) translateScoped(w io.Writer, dot types.Type, nodeType parse.NodeType, pipe *parse.PipeNode, list, elseList *parse.ListNode) error {
   377  	io.WriteString(w, "if eval := ")
   378  	typ, err := t.translatePipe(w, dot, pipe)
   379  	if err != nil {
   380  		return err
   381  	}
   382  	io.WriteString(w, "; ")
   383  	if err := writeTruthiness(w, typ); err != nil {
   384  		return err
   385  	}
   386  	io.WriteString(w, "{\n")
   387  	t.pushScope()
   388  
   389  	if nodeType == parse.NodeWith {
   390  		io.WriteString(w, "dot := eval\n_ = dot\n")
   391  	}
   392  
   393  	if nodeType == parse.NodeRange {
   394  		var elem types.Type
   395  		switch typ := typ.(type) {
   396  		case *types.Chan:
   397  			elem = typ.Elem()
   398  		case *types.Slice:
   399  			elem = typ.Elem()
   400  		case *types.Array:
   401  			elem = typ.Elem()
   402  		default:
   403  			return fmt.Errorf("range over non-iterable: %v", pipe.Pos)
   404  		}
   405  
   406  		switch len(pipe.Decl) {
   407  		case 0:
   408  			io.WriteString(w, "for _, dot := range eval {\n_ = dot\n")
   409  		case 1:
   410  			ident := pipe.Decl[0].Ident[0][1:]
   411  			fmt.Fprintf(w, "for _, %s%s := range eval {\ndot := %s%s\n_ = dot\n", varPrefix, ident, varPrefix, ident)
   412  			t.addToScope(ident, elem)
   413  		case 2:
   414  			index := pipe.Decl[0].Ident[0][1:]
   415  			ident := pipe.Decl[1].Ident[0][1:]
   416  			t.addToScope(index, types.Typ[types.Int64])
   417  			t.addToScope(ident, elem)
   418  			fmt.Fprintf(w, "for %s%s, %s%s := range eval {\n_ = %s%s\ndot := %s%s\n_ = dot\n", varPrefix, index, varPrefix, ident, varPrefix, index, varPrefix, ident)
   419  		default:
   420  			return fmt.Errorf("too many declarations for range")
   421  		}
   422  
   423  		if err := t.translateNode(w, list, elem); err != nil {
   424  			return err
   425  		}
   426  
   427  		io.WriteString(w, "}\n")
   428  	} else {
   429  		switch len(pipe.Decl) {
   430  		case 0:
   431  		case 1:
   432  			ident := pipe.Decl[0].Ident[0][1:]
   433  			fmt.Fprintf(w, "%s%s := eval\n_ = %s%s\n", varPrefix, ident, varPrefix, ident)
   434  			t.addToScope(ident, typ)
   435  		default:
   436  			return fmt.Errorf("too many declarations")
   437  		}
   438  
   439  		if err := t.translateNode(w, list, dot); err != nil {
   440  			return err
   441  		}
   442  	}
   443  
   444  	t.popScope()
   445  	io.WriteString(w, "}")
   446  	if elseList != nil {
   447  		io.WriteString(w, " else {\n")
   448  		if err := t.translateNode(w, elseList, dot); err != nil {
   449  			return err
   450  		}
   451  		io.WriteString(w, "}")
   452  	}
   453  	io.WriteString(w, "\n")
   454  	return nil
   455  }
   456  
   457  func (t *Translator) translatePipe(w io.Writer, dot types.Type, pipe *parse.PipeNode) (types.Type, error) {
   458  	if pipe == nil {
   459  		io.WriteString(w, "nil")
   460  		return types.Typ[types.UntypedNil], nil
   461  	} else {
   462  		return t.translateCommand(w, dot, pipe.Cmds[len(pipe.Cmds)-1], pipe.Cmds[:len(pipe.Cmds)-1])
   463  	}
   464  }
   465  
   466  func (t *Translator) translateCall(w io.Writer, dot types.Type, args []parse.Node, nextCommands []*parse.CommandNode) error {
   467  	io.WriteString(w, "(")
   468  	for i, arg := range args {
   469  		if i != 0 {
   470  			io.WriteString(w, ", ")
   471  		}
   472  		if _, err := t.translateArg(w, dot, arg); err != nil {
   473  			return err
   474  		}
   475  	}
   476  	if len(nextCommands) != 0 {
   477  		if len(args) != 0 {
   478  			io.WriteString(w, ", ")
   479  		}
   480  		if _, err := t.translateCommand(w, dot, nextCommands[len(nextCommands)-1], nextCommands[:len(nextCommands)-1]); err != nil {
   481  			return err
   482  		}
   483  	}
   484  	io.WriteString(w, ")")
   485  	return nil
   486  }
   487  
   488  func (t *Translator) translateCommand(w io.Writer, dot types.Type, cmd *parse.CommandNode, nextCommands []*parse.CommandNode) (types.Type, error) {
   489  	action := cmd.Args[0]
   490  	args := cmd.Args[1:]
   491  
   492  	switch action := action.(type) {
   493  	case *parse.ChainNode:
   494  		return t.translateChain(w, dot, action, args, nextCommands)
   495  	case *parse.FieldNode:
   496  		return t.translateField(w, dot, action, args, nextCommands)
   497  	case *parse.IdentifierNode:
   498  		return t.translateFunction(w, dot, action, args, nextCommands)
   499  	case *parse.PipeNode:
   500  		// We ignore args, nextCommands in pipes
   501  		return t.translatePipe(w, dot, action)
   502  	case *parse.VariableNode:
   503  		return t.translateVariable(w, dot, action, args, nextCommands)
   504  	}
   505  
   506  	if len(args) > 0 || len(nextCommands) > 0 {
   507  		return nil, fmt.Errorf("dunno what to do with args %v %v %v", cmd.Args, action.Type(), nextCommands)
   508  	}
   509  
   510  	switch action := action.(type) {
   511  	case *parse.BoolNode:
   512  		_, err := fmt.Fprint(w, action.True)
   513  		return types.Typ[types.Bool], err
   514  	case *parse.DotNode:
   515  		_, err := io.WriteString(w, "dot")
   516  		return dot, err
   517  	case *parse.NilNode:
   518  		return nil, fmt.Errorf("nil is not a command")
   519  	case *parse.NumberNode:
   520  		if action.IsInt {
   521  			_, err := fmt.Fprint(w, action.Int64)
   522  			return types.Typ[types.Int64], err
   523  		} else if action.IsUint {
   524  			_, err := fmt.Fprint(w, action.Uint64)
   525  			return types.Typ[types.Uint64], err
   526  		} else if action.IsFloat {
   527  			_, err := fmt.Fprint(w, action.Float64)
   528  			return types.Typ[types.Float64], err
   529  		} else if action.IsComplex {
   530  			_, err := fmt.Fprint(w, action.Complex128)
   531  			return types.Typ[types.Complex128], err
   532  		} else {
   533  			return nil, fmt.Errorf("unknown number node %v", action)
   534  		}
   535  	case *parse.StringNode:
   536  		_, err := fmt.Fprintf(w, "%q", action.Text)
   537  		return types.Typ[types.String], err
   538  	default:
   539  		return nil, fmt.Errorf("unknown pipe node %s, %v", action.String(), action.Type())
   540  	}
   541  }
   542  
   543  func (t *Translator) translateArg(w io.Writer, dot types.Type, arg parse.Node) (types.Type, error) {
   544  	switch arg := arg.(type) {
   545  	case *parse.BoolNode:
   546  		_, err := fmt.Fprint(w, arg.True)
   547  		return types.Typ[types.Bool], err
   548  	case *parse.ChainNode:
   549  		return t.translateChain(w, dot, arg, nil, nil)
   550  	case *parse.DotNode:
   551  		_, err := io.WriteString(w, "dot")
   552  		return dot, err
   553  	case *parse.FieldNode:
   554  		return t.translateField(w, dot, arg, nil, nil)
   555  	case *parse.IdentifierNode:
   556  		return t.translateFunction(w, dot, arg, nil, nil)
   557  	case *parse.NilNode:
   558  		_, err := io.WriteString(w, "nil")
   559  		return types.Typ[types.UntypedNil], err
   560  	case *parse.NumberNode:
   561  		if arg.IsInt {
   562  			_, err := fmt.Fprint(w, arg.Int64)
   563  			return types.Typ[types.Int64], err
   564  		} else {
   565  			return nil, fmt.Errorf("unknown number node %v", arg)
   566  		}
   567  	case *parse.PipeNode:
   568  		if len(arg.Decl) > 0 {
   569  			// TODO(bouk): do (is it even possible?)
   570  			return nil, fmt.Errorf("can't process inline variable assignment right now")
   571  		}
   572  		return t.translatePipe(w, dot, arg)
   573  	case *parse.StringNode:
   574  		_, err := fmt.Fprintf(w, "%q", arg.Text)
   575  		return types.Typ[types.String], err
   576  	case *parse.VariableNode:
   577  		return t.translateVariable(w, dot, arg, nil, nil)
   578  	default:
   579  		return nil, fmt.Errorf("unknown arg %s, %v", arg.String(), arg.Type())
   580  	}
   581  }
   582  
   583  func (t *Translator) translateChain(w io.Writer, dot types.Type, node *parse.ChainNode, args []parse.Node, nextCommands []*parse.CommandNode) (types.Type, error) {
   584  	var buf bytes.Buffer
   585  	typ, err := t.translateArg(&buf, dot, node.Node)
   586  	if err != nil {
   587  		return nil, err
   588  	}
   589  	return t.translateFieldChain(w, dot, &buf, typ, node.Field, args, nextCommands)
   590  }
   591  
   592  func (t *Translator) translateVariable(w io.Writer, dot types.Type, node *parse.VariableNode, args []parse.Node, nextCommands []*parse.CommandNode) (types.Type, error) {
   593  	ident := node.Ident[0][1:]
   594  	if len(node.Ident) > 1 && (len(args) != 0 || len(nextCommands) != 0) {
   595  		return nil, fmt.Errorf("can't call variable %s", node.Ident[0])
   596  	}
   597  	typ, err := t.findVariable(ident)
   598  	if err != nil {
   599  		return nil, err
   600  	}
   601  
   602  	return t.translateFieldChain(w, dot, constantWriterTo(varPrefix+ident), typ, node.Ident[1:], args, nextCommands)
   603  }
   604  
   605  func (t *Translator) generateErrorFunction(typ types.Type) string {
   606  	name, ok := t.errorFunctions.At(typ).(string)
   607  	if !ok {
   608  		name = t.generateFunctionName()
   609  		typeName := t.typeName(typ)
   610  
   611  		t.generatedFunctions = append(t.generatedFunctions, fmt.Sprintf(`
   612  func %s(value %s, err error) %s {
   613  	if err != nil {
   614  		panic(err)
   615  	}
   616  	return value
   617  }`, name, typeName, typeName))
   618  		t.errorFunctions.Set(typ, name)
   619  	}
   620  	return name
   621  }
   622  
   623  func (t *Translator) getFunction(ident string) (*types.Signature, string, error) {
   624  	if f, ok := t.Funcs[ident]; ok {
   625  		pkgName := t.importPackage(f.Pkg().Path())
   626  		return f.Type().(*types.Signature), fmt.Sprintf("%s.%s", pkgName, f.Name()), nil
   627  	} else if f, ok := builtinFuncs[ident]; ok {
   628  		pkgName := t.importPackage(f.Pkg().Path())
   629  		return f.Type().(*types.Signature), fmt.Sprintf("%s.%s", pkgName, f.Name()), nil
   630  	} else {
   631  		return nil, "", fmt.Errorf("unknown function %s", ident)
   632  	}
   633  }
   634  
   635  func (t *Translator) translateFunction(w io.Writer, dot types.Type, ident *parse.IdentifierNode, args []parse.Node, nextCommands []*parse.CommandNode) (types.Type, error) {
   636  	typ, fName, err := t.getFunction(ident.Ident)
   637  	if err != nil {
   638  		return nil, err
   639  	}
   640  
   641  	numOut := typ.Results().Len()
   642  
   643  	if numOut == 2 {
   644  		fmt.Fprintf(w, "%s(", t.generateErrorFunction(typ))
   645  	} else if numOut != 1 {
   646  		return nil, fmt.Errorf("only support 1, 2 output variable %s", ident.Ident)
   647  	}
   648  
   649  	io.WriteString(w, fName)
   650  
   651  	if err := t.translateCall(w, dot, args, nextCommands); err != nil {
   652  		return nil, err
   653  	}
   654  
   655  	if numOut == 2 {
   656  		io.WriteString(w, ")")
   657  	}
   658  
   659  	return typ.Results().At(0).Type(), nil
   660  }
   661  
   662  func (t *Translator) translateField(w io.Writer, dot types.Type, field *parse.FieldNode, args []parse.Node, nextCommands []*parse.CommandNode) (types.Type, error) {
   663  	return t.translateFieldChain(w, dot, constantWriterTo("dot"), dot, field.Ident, args, nextCommands)
   664  }
   665  
   666  func (t *Translator) translateFieldChain(w io.Writer, dot types.Type, dotCode io.WriterTo, typ types.Type, fields []string, args []parse.Node, nextCommands []*parse.CommandNode) (types.Type, error) {
   667  	var buf bytes.Buffer
   668  	guards := []string{}
   669  	for i, name := range fields {
   670  		obj, _, _ := types.LookupFieldOrMethod(typ, true, nil, name)
   671  
   672  		switch obj := obj.(type) {
   673  		case *types.Func:
   674  			sig := obj.Type().(*types.Signature)
   675  			out := sig.Results()
   676  			numOut := out.Len()
   677  			returnTyp := out.At(0).Type()
   678  			if numOut == 2 {
   679  				guards = append(guards, fmt.Sprintf("%s(", t.generateErrorFunction(returnTyp)))
   680  			} else if numOut != 1 {
   681  				return nil, fmt.Errorf("only support 1, 2 output variable %s.%s", t.typeName(typ), obj.Name())
   682  			}
   683  			fmt.Fprintf(&buf, ".%s", name)
   684  
   685  			var err error
   686  			if i == len(fields)-1 {
   687  				err = t.translateCall(&buf, dot, args, nextCommands)
   688  			} else {
   689  				err = t.translateCall(&buf, dot, nil, nil)
   690  			}
   691  			if err != nil {
   692  				return nil, err
   693  			}
   694  			if numOut == 2 {
   695  				io.WriteString(&buf, ")")
   696  			}
   697  			typ = returnTyp
   698  		case *types.Var:
   699  			fmt.Fprintf(&buf, ".%s", name)
   700  			typ = obj.Type()
   701  		default:
   702  			return nil, fmt.Errorf("unknown field %s for type %s", name, typ.String())
   703  		}
   704  	}
   705  	for i := len(guards) - 1; i >= 0; i-- {
   706  		io.WriteString(w, guards[i])
   707  	}
   708  	_, err := dotCode.WriteTo(w)
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  	_, err = buf.WriteTo(w)
   713  	return typ, err
   714  }
   715  
   716  func (t *Translator) typeName(typ types.Type) string {
   717  	switch obj := typ.(type) {
   718  	case *types.Array:
   719  		return fmt.Sprintf("[%d]%s", obj.Len(), t.typeName(obj.Elem()))
   720  	case *types.Chan:
   721  		return fmt.Sprintf("chan %s", t.typeName(obj.Elem()))
   722  	case *types.Map:
   723  		return fmt.Sprintf("map[%s]%s", t.typeName(obj.Key()), t.typeName(obj.Elem()))
   724  	case *types.Named:
   725  		name := obj.Obj()
   726  		return t.importPackage(name.Pkg().Path()) + "." + name.Name()
   727  	case *types.Pointer:
   728  		return fmt.Sprintf("*%s", t.typeName(obj.Elem()))
   729  	case *types.Slice:
   730  		return fmt.Sprintf("[]%s", t.typeName(obj.Elem()))
   731  	default:
   732  		return typ.String()
   733  	}
   734  }