Black Lives Matter. Support the Equal Justice Initiative.

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