Source file src/go/types/exprstring.go

     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  		fmt.Fprintf(buf, "(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  		WriteExpr(buf, x.Type)
    57  		buf.WriteByte('{')
    58  		if len(x.Elts) > 0 {
    59  			buf.WriteString("…")
    60  		}
    61  		buf.WriteByte('}')
    62  
    63  	case *ast.ParenExpr:
    64  		buf.WriteByte('(')
    65  		WriteExpr(buf, x.X)
    66  		buf.WriteByte(')')
    67  
    68  	case *ast.SelectorExpr:
    69  		WriteExpr(buf, x.X)
    70  		buf.WriteByte('.')
    71  		buf.WriteString(x.Sel.Name)
    72  
    73  	case *ast.IndexExpr, *ast.IndexListExpr:
    74  		ix := typeparams.UnpackIndexExpr(x)
    75  		WriteExpr(buf, ix.X)
    76  		buf.WriteByte('[')
    77  		writeExprList(buf, ix.Indices)
    78  		buf.WriteByte(']')
    79  
    80  	case *ast.SliceExpr:
    81  		WriteExpr(buf, x.X)
    82  		buf.WriteByte('[')
    83  		if x.Low != nil {
    84  			WriteExpr(buf, x.Low)
    85  		}
    86  		buf.WriteByte(':')
    87  		if x.High != nil {
    88  			WriteExpr(buf, x.High)
    89  		}
    90  		if x.Slice3 {
    91  			buf.WriteByte(':')
    92  			if x.Max != nil {
    93  				WriteExpr(buf, x.Max)
    94  			}
    95  		}
    96  		buf.WriteByte(']')
    97  
    98  	case *ast.TypeAssertExpr:
    99  		WriteExpr(buf, x.X)
   100  		buf.WriteString(".(")
   101  		WriteExpr(buf, x.Type)
   102  		buf.WriteByte(')')
   103  
   104  	case *ast.CallExpr:
   105  		WriteExpr(buf, x.Fun)
   106  		buf.WriteByte('(')
   107  		writeExprList(buf, x.Args)
   108  		if hasDots(x) {
   109  			buf.WriteString("...")
   110  		}
   111  		buf.WriteByte(')')
   112  
   113  	case *ast.StarExpr:
   114  		buf.WriteByte('*')
   115  		WriteExpr(buf, x.X)
   116  
   117  	case *ast.UnaryExpr:
   118  		buf.WriteString(x.Op.String())
   119  		WriteExpr(buf, x.X)
   120  
   121  	case *ast.BinaryExpr:
   122  		WriteExpr(buf, x.X)
   123  		buf.WriteByte(' ')
   124  		buf.WriteString(x.Op.String())
   125  		buf.WriteByte(' ')
   126  		WriteExpr(buf, x.Y)
   127  
   128  	case *ast.ArrayType:
   129  		buf.WriteByte('[')
   130  		if x.Len != nil {
   131  			WriteExpr(buf, x.Len)
   132  		}
   133  		buf.WriteByte(']')
   134  		WriteExpr(buf, x.Elt)
   135  
   136  	case *ast.StructType:
   137  		buf.WriteString("struct{")
   138  		writeFieldList(buf, x.Fields.List, "; ", false)
   139  		buf.WriteByte('}')
   140  
   141  	case *ast.FuncType:
   142  		buf.WriteString("func")
   143  		writeSigExpr(buf, x)
   144  
   145  	case *ast.InterfaceType:
   146  		buf.WriteString("interface{")
   147  		writeFieldList(buf, x.Methods.List, "; ", true)
   148  		buf.WriteByte('}')
   149  
   150  	case *ast.MapType:
   151  		buf.WriteString("map[")
   152  		WriteExpr(buf, x.Key)
   153  		buf.WriteByte(']')
   154  		WriteExpr(buf, x.Value)
   155  
   156  	case *ast.ChanType:
   157  		var s string
   158  		switch x.Dir {
   159  		case ast.SEND:
   160  			s = "chan<- "
   161  		case ast.RECV:
   162  			s = "<-chan "
   163  		default:
   164  			s = "chan "
   165  		}
   166  		buf.WriteString(s)
   167  		WriteExpr(buf, x.Value)
   168  	}
   169  }
   170  
   171  func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
   172  	buf.WriteByte('(')
   173  	writeFieldList(buf, sig.Params.List, ", ", false)
   174  	buf.WriteByte(')')
   175  
   176  	res := sig.Results
   177  	n := res.NumFields()
   178  	if n == 0 {
   179  		// no result
   180  		return
   181  	}
   182  
   183  	buf.WriteByte(' ')
   184  	if n == 1 && len(res.List[0].Names) == 0 {
   185  		// single unnamed result
   186  		WriteExpr(buf, res.List[0].Type)
   187  		return
   188  	}
   189  
   190  	// multiple or named result(s)
   191  	buf.WriteByte('(')
   192  	writeFieldList(buf, res.List, ", ", false)
   193  	buf.WriteByte(')')
   194  }
   195  
   196  func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) {
   197  	for i, f := range list {
   198  		if i > 0 {
   199  			buf.WriteString(sep)
   200  		}
   201  
   202  		// field list names
   203  		writeIdentList(buf, f.Names)
   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  }
   221  
   222  func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
   223  	for i, x := range list {
   224  		if i > 0 {
   225  			buf.WriteString(", ")
   226  		}
   227  		buf.WriteString(x.Name)
   228  	}
   229  }
   230  
   231  func writeExprList(buf *bytes.Buffer, list []ast.Expr) {
   232  	for i, x := range list {
   233  		if i > 0 {
   234  			buf.WriteString(", ")
   235  		}
   236  		WriteExpr(buf, x)
   237  	}
   238  }
   239  

View as plain text