github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/go/types/exprstring.go (about) 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 "go/ast" 12 ) 13 14 // ExprString returns the (possibly shortened) string representation for x. 15 // Shortened representations are suitable for user interfaces but may not 16 // necessarily follow Go syntax. 17 func ExprString(x ast.Expr) string { 18 var buf bytes.Buffer 19 WriteExpr(&buf, x) 20 return buf.String() 21 } 22 23 // WriteExpr writes the (possibly shortened) string representation for x to buf. 24 // Shortened representations are suitable for user interfaces but may not 25 // necessarily follow Go syntax. 26 func WriteExpr(buf *bytes.Buffer, x ast.Expr) { 27 // The AST preserves source-level parentheses so there is 28 // no need to introduce them here to correct for different 29 // operator precedences. (This assumes that the AST was 30 // generated by a Go parser.) 31 32 switch x := x.(type) { 33 default: 34 buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr 35 36 case *ast.Ident: 37 buf.WriteString(x.Name) 38 39 case *ast.Ellipsis: 40 buf.WriteString("...") 41 if x.Elt != nil { 42 WriteExpr(buf, x.Elt) 43 } 44 45 case *ast.BasicLit: 46 buf.WriteString(x.Value) 47 48 case *ast.FuncLit: 49 buf.WriteByte('(') 50 WriteExpr(buf, x.Type) 51 buf.WriteString(" literal)") // shortened 52 53 case *ast.CompositeLit: 54 buf.WriteByte('(') 55 WriteExpr(buf, x.Type) 56 buf.WriteString(" literal)") // shortened 57 58 case *ast.ParenExpr: 59 buf.WriteByte('(') 60 WriteExpr(buf, x.X) 61 buf.WriteByte(')') 62 63 case *ast.SelectorExpr: 64 WriteExpr(buf, x.X) 65 buf.WriteByte('.') 66 buf.WriteString(x.Sel.Name) 67 68 case *ast.IndexExpr: 69 WriteExpr(buf, x.X) 70 buf.WriteByte('[') 71 WriteExpr(buf, x.Index) 72 buf.WriteByte(']') 73 74 case *ast.SliceExpr: 75 WriteExpr(buf, x.X) 76 buf.WriteByte('[') 77 if x.Low != nil { 78 WriteExpr(buf, x.Low) 79 } 80 buf.WriteByte(':') 81 if x.High != nil { 82 WriteExpr(buf, x.High) 83 } 84 if x.Slice3 { 85 buf.WriteByte(':') 86 if x.Max != nil { 87 WriteExpr(buf, x.Max) 88 } 89 } 90 buf.WriteByte(']') 91 92 case *ast.TypeAssertExpr: 93 WriteExpr(buf, x.X) 94 buf.WriteString(".(") 95 WriteExpr(buf, x.Type) 96 buf.WriteByte(')') 97 98 case *ast.CallExpr: 99 WriteExpr(buf, x.Fun) 100 buf.WriteByte('(') 101 for i, arg := range x.Args { 102 if i > 0 { 103 buf.WriteString(", ") 104 } 105 WriteExpr(buf, arg) 106 } 107 if x.Ellipsis.IsValid() { 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, "; ", 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, "; ", 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, ", ", 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, ", ", false) 192 buf.WriteByte(')') 193 } 194 195 func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) { 196 for i, f := range fields.List { 197 if i > 0 { 198 buf.WriteString(sep) 199 } 200 201 // field list names 202 for i, name := range f.Names { 203 if i > 0 { 204 buf.WriteString(", ") 205 } 206 buf.WriteString(name.Name) 207 } 208 209 // types of interface methods consist of signatures only 210 if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface { 211 writeSigExpr(buf, sig) 212 continue 213 } 214 215 // named fields are separated with a blank from the field type 216 if len(f.Names) > 0 { 217 buf.WriteByte(' ') 218 } 219 220 WriteExpr(buf, f.Type) 221 222 // ignore tag 223 } 224 }