Home | History | Annotate | Download | only in 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 	"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 }
    225