...

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

View as plain text