exprstring.go raw

   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  	"fmt"
  12  	"go/ast"
  13  )
  14  
  15  // ExprString returns the (possibly shortened) string representation for x.
  16  // Shortened representations are suitable for user interfaces but may not
  17  // necessarily follow Go syntax.
  18  func ExprString(x ast.Expr) string {
  19  	var buf bytes.Buffer
  20  	WriteExpr(&buf, x)
  21  	return buf.String()
  22  }
  23  
  24  // WriteExpr writes the (possibly shortened) string representation for x to buf.
  25  // Shortened representations are suitable for user interfaces but may not
  26  // necessarily follow Go syntax.
  27  func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
  28  	// The AST preserves source-level parentheses so there is
  29  	// no need to introduce them here to correct for different
  30  	// operator precedences. (This assumes that the AST was
  31  	// generated by a Go parser.)
  32  
  33  	switch x := x.(type) {
  34  	default:
  35  		fmt.Fprintf(buf, "(ast: %T)", x) // nil, ast.BadExpr, ast.KeyValueExpr
  36  
  37  	case *ast.Ident:
  38  		buf.WriteString(x.Name)
  39  
  40  	case *ast.Ellipsis:
  41  		buf.WriteString("...")
  42  		if x.Elt != nil {
  43  			WriteExpr(buf, x.Elt)
  44  		}
  45  
  46  	case *ast.BasicLit:
  47  		buf.WriteString(x.Value)
  48  
  49  	case *ast.FuncLit:
  50  		buf.WriteByte('(')
  51  		WriteExpr(buf, x.Type)
  52  		buf.WriteString(" literal)") // shortened
  53  
  54  	case *ast.CompositeLit:
  55  		WriteExpr(buf, x.Type)
  56  		buf.WriteByte('{')
  57  		if len(x.Elts) > 0 {
  58  			buf.WriteString("…")
  59  		}
  60  		buf.WriteByte('}')
  61  
  62  	case *ast.ParenExpr:
  63  		buf.WriteByte('(')
  64  		WriteExpr(buf, x.X)
  65  		buf.WriteByte(')')
  66  
  67  	case *ast.SelectorExpr:
  68  		WriteExpr(buf, x.X)
  69  		buf.WriteByte('.')
  70  		buf.WriteString(x.Sel.Name)
  71  
  72  	case *ast.IndexExpr, *ast.IndexListExpr:
  73  		ix := unpackIndexedExpr(x)
  74  		WriteExpr(buf, ix.x)
  75  		buf.WriteByte('[')
  76  		writeExprList(buf, ix.indices)
  77  		buf.WriteByte(']')
  78  
  79  	case *ast.SliceExpr:
  80  		WriteExpr(buf, x.X)
  81  		buf.WriteByte('[')
  82  		if x.Low != nil {
  83  			WriteExpr(buf, x.Low)
  84  		}
  85  		buf.WriteByte(':')
  86  		if x.High != nil {
  87  			WriteExpr(buf, x.High)
  88  		}
  89  		if x.Slice3 {
  90  			buf.WriteByte(':')
  91  			if x.Max != nil {
  92  				WriteExpr(buf, x.Max)
  93  			}
  94  		}
  95  		buf.WriteByte(']')
  96  
  97  	case *ast.TypeAssertExpr:
  98  		WriteExpr(buf, x.X)
  99  		buf.WriteString(".(")
 100  		WriteExpr(buf, x.Type)
 101  		buf.WriteByte(')')
 102  
 103  	case *ast.CallExpr:
 104  		WriteExpr(buf, x.Fun)
 105  		buf.WriteByte('(')
 106  		writeExprList(buf, x.Args)
 107  		if hasDots(x) {
 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.List, "; ", 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.List, "; ", 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.List, ", ", 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.List, ", ", false)
 192  	buf.WriteByte(')')
 193  }
 194  
 195  func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) {
 196  	for i, f := range list {
 197  		if i > 0 {
 198  			buf.WriteString(sep)
 199  		}
 200  
 201  		// field list names
 202  		writeIdentList(buf, f.Names)
 203  
 204  		// types of interface methods consist of signatures only
 205  		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
 206  			writeSigExpr(buf, sig)
 207  			continue
 208  		}
 209  
 210  		// named fields are separated with a blank from the field type
 211  		if len(f.Names) > 0 {
 212  			buf.WriteByte(' ')
 213  		}
 214  
 215  		WriteExpr(buf, f.Type)
 216  
 217  		// ignore tag
 218  	}
 219  }
 220  
 221  func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
 222  	for i, x := range list {
 223  		if i > 0 {
 224  			buf.WriteString(", ")
 225  		}
 226  		buf.WriteString(x.Name)
 227  	}
 228  }
 229  
 230  func writeExprList(buf *bytes.Buffer, list []ast.Expr) {
 231  	for i, x := range list {
 232  		if i > 0 {
 233  			buf.WriteString(", ")
 234  		}
 235  		WriteExpr(buf, x)
 236  	}
 237  }
 238