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  )
    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  

View as plain text