...
Run Format

Source file src/go/types/exprstring.go

Documentation: go/types

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

View as plain text