github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/exprstring.go (about)

     1  // Copyright 2013 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  // This file implements printing of expressions.
     6  
     7  package types
     8  
     9  import (
    10  	"bytes"
    11  	"go/ast"
    12  )
    13  
    14  // ExprString returns the (possibly simplified) string representation for x.
    15  func ExprString(x ast.Expr) string {
    16  	var buf bytes.Buffer
    17  	WriteExpr(&buf, x)
    18  	return buf.String()
    19  }
    20  
    21  // WriteExpr writes the (possibly simplified) string representation for x to buf.
    22  func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
    23  	// The AST preserves source-level parentheses so there is
    24  	// no need to introduce them here to correct for different
    25  	// operator precedences. (This assumes that the AST was
    26  	// generated by a Go parser.)
    27  
    28  	switch x := x.(type) {
    29  	default:
    30  		buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
    31  
    32  	case *ast.Ident:
    33  		buf.WriteString(x.Name)
    34  
    35  	case *ast.Ellipsis:
    36  		buf.WriteString("...")
    37  		if x.Elt != nil {
    38  			WriteExpr(buf, x.Elt)
    39  		}
    40  
    41  	case *ast.BasicLit:
    42  		buf.WriteString(x.Value)
    43  
    44  	case *ast.FuncLit:
    45  		buf.WriteByte('(')
    46  		WriteExpr(buf, x.Type)
    47  		buf.WriteString(" literal)") // simplified
    48  
    49  	case *ast.CompositeLit:
    50  		buf.WriteByte('(')
    51  		WriteExpr(buf, x.Type)
    52  		buf.WriteString(" literal)") // simplified
    53  
    54  	case *ast.ParenExpr:
    55  		buf.WriteByte('(')
    56  		WriteExpr(buf, x.X)
    57  		buf.WriteByte(')')
    58  
    59  	case *ast.SelectorExpr:
    60  		WriteExpr(buf, x.X)
    61  		buf.WriteByte('.')
    62  		buf.WriteString(x.Sel.Name)
    63  
    64  	case *ast.IndexExpr:
    65  		WriteExpr(buf, x.X)
    66  		buf.WriteByte('[')
    67  		WriteExpr(buf, x.Index)
    68  		buf.WriteByte(']')
    69  
    70  	case *ast.SliceExpr:
    71  		WriteExpr(buf, x.X)
    72  		buf.WriteByte('[')
    73  		if x.Low != nil {
    74  			WriteExpr(buf, x.Low)
    75  		}
    76  		buf.WriteByte(':')
    77  		if x.High != nil {
    78  			WriteExpr(buf, x.High)
    79  		}
    80  		if x.Slice3 {
    81  			buf.WriteByte(':')
    82  			if x.Max != nil {
    83  				WriteExpr(buf, x.Max)
    84  			}
    85  		}
    86  		buf.WriteByte(']')
    87  
    88  	case *ast.TypeAssertExpr:
    89  		WriteExpr(buf, x.X)
    90  		buf.WriteString(".(")
    91  		WriteExpr(buf, x.Type)
    92  		buf.WriteByte(')')
    93  
    94  	case *ast.CallExpr:
    95  		WriteExpr(buf, x.Fun)
    96  		buf.WriteByte('(')
    97  		for i, arg := range x.Args {
    98  			if i > 0 {
    99  				buf.WriteString(", ")
   100  			}
   101  			WriteExpr(buf, arg)
   102  		}
   103  		if x.Ellipsis.IsValid() {
   104  			buf.WriteString("...")
   105  		}
   106  		buf.WriteByte(')')
   107  
   108  	case *ast.StarExpr:
   109  		buf.WriteByte('*')
   110  		WriteExpr(buf, x.X)
   111  
   112  	case *ast.UnaryExpr:
   113  		buf.WriteString(x.Op.String())
   114  		WriteExpr(buf, x.X)
   115  
   116  	case *ast.BinaryExpr:
   117  		WriteExpr(buf, x.X)
   118  		buf.WriteByte(' ')
   119  		buf.WriteString(x.Op.String())
   120  		buf.WriteByte(' ')
   121  		WriteExpr(buf, x.Y)
   122  
   123  	case *ast.ArrayType:
   124  		buf.WriteByte('[')
   125  		if x.Len != nil {
   126  			WriteExpr(buf, x.Len)
   127  		}
   128  		buf.WriteByte(']')
   129  		WriteExpr(buf, x.Elt)
   130  
   131  	case *ast.StructType:
   132  		buf.WriteString("struct{")
   133  		writeFieldList(buf, x.Fields, "; ", false)
   134  		buf.WriteByte('}')
   135  
   136  	case *ast.FuncType:
   137  		buf.WriteString("func")
   138  		writeSigExpr(buf, x)
   139  
   140  	case *ast.InterfaceType:
   141  		buf.WriteString("interface{")
   142  		writeFieldList(buf, x.Methods, "; ", true)
   143  		buf.WriteByte('}')
   144  
   145  	case *ast.MapType:
   146  		buf.WriteString("map[")
   147  		WriteExpr(buf, x.Key)
   148  		buf.WriteByte(']')
   149  		WriteExpr(buf, x.Value)
   150  
   151  	case *ast.ChanType:
   152  		var s string
   153  		switch x.Dir {
   154  		case ast.SEND:
   155  			s = "chan<- "
   156  		case ast.RECV:
   157  			s = "<-chan "
   158  		default:
   159  			s = "chan "
   160  		}
   161  		buf.WriteString(s)
   162  		WriteExpr(buf, x.Value)
   163  	}
   164  }
   165  
   166  func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
   167  	buf.WriteByte('(')
   168  	writeFieldList(buf, sig.Params, ", ", false)
   169  	buf.WriteByte(')')
   170  
   171  	res := sig.Results
   172  	n := res.NumFields()
   173  	if n == 0 {
   174  		// no result
   175  		return
   176  	}
   177  
   178  	buf.WriteByte(' ')
   179  	if n == 1 && len(res.List[0].Names) == 0 {
   180  		// single unnamed result
   181  		WriteExpr(buf, res.List[0].Type)
   182  		return
   183  	}
   184  
   185  	// multiple or named result(s)
   186  	buf.WriteByte('(')
   187  	writeFieldList(buf, res, ", ", false)
   188  	buf.WriteByte(')')
   189  }
   190  
   191  func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
   192  	for i, f := range fields.List {
   193  		if i > 0 {
   194  			buf.WriteString(sep)
   195  		}
   196  
   197  		// field list names
   198  		for i, name := range f.Names {
   199  			if i > 0 {
   200  				buf.WriteString(", ")
   201  			}
   202  			buf.WriteString(name.Name)
   203  		}
   204  
   205  		// types of interface methods consist of signatures only
   206  		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
   207  			writeSigExpr(buf, sig)
   208  			continue
   209  		}
   210  
   211  		// named fields are separated with a blank from the field type
   212  		if len(f.Names) > 0 {
   213  			buf.WriteByte(' ')
   214  		}
   215  
   216  		WriteExpr(buf, f.Type)
   217  
   218  		// ignore tag
   219  	}
   220  }