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

View as plain text