github.com/goplus/gop@v1.2.6/x/typesutil/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 typesutil
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  
    13  	"github.com/goplus/gop/ast"
    14  	"github.com/goplus/gop/x/typesutil/typeparams"
    15  )
    16  
    17  // ExprString returns the (possibly shortened) string representation for x.
    18  // Shortened representations are suitable for user interfaces but may not
    19  // necessarily follow Go syntax.
    20  func ExprString(x ast.Expr) string {
    21  	var buf bytes.Buffer
    22  	WriteExpr(&buf, x)
    23  	return buf.String()
    24  }
    25  
    26  // WriteExpr writes the (possibly shortened) string representation for x to buf.
    27  // Shortened representations are suitable for user interfaces but may not
    28  // necessarily follow Go syntax.
    29  func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
    30  	// The AST preserves source-level parentheses so there is
    31  	// no need to introduce them here to correct for different
    32  	// operator precedences. (This assumes that the AST was
    33  	// generated by a Go parser.)
    34  
    35  	switch x := x.(type) {
    36  	default:
    37  		fmt.Fprintf(buf, "(ast: %T)", x) // nil, ast.BadExpr, ast.KeyValueExpr
    38  
    39  	case *ast.Ident:
    40  		buf.WriteString(x.Name)
    41  
    42  	case *ast.Ellipsis:
    43  		buf.WriteString("...")
    44  		if x.Elt != nil {
    45  			WriteExpr(buf, x.Elt)
    46  		}
    47  
    48  	case *ast.BasicLit:
    49  		buf.WriteString(x.Value)
    50  
    51  	case *ast.FuncLit:
    52  		buf.WriteByte('(')
    53  		WriteExpr(buf, x.Type)
    54  		buf.WriteString(" literal)") // shortened
    55  
    56  	case *ast.CompositeLit:
    57  		WriteExpr(buf, x.Type)
    58  		buf.WriteByte('{')
    59  		if len(x.Elts) > 0 {
    60  			buf.WriteString("…")
    61  		}
    62  		buf.WriteByte('}')
    63  
    64  	case *ast.ParenExpr:
    65  		buf.WriteByte('(')
    66  		WriteExpr(buf, x.X)
    67  		buf.WriteByte(')')
    68  
    69  	case *ast.SelectorExpr:
    70  		WriteExpr(buf, x.X)
    71  		buf.WriteByte('.')
    72  		buf.WriteString(x.Sel.Name)
    73  
    74  	case *ast.IndexExpr, *ast.IndexListExpr:
    75  		ix := typeparams.UnpackIndexExpr(x)
    76  		WriteExpr(buf, ix.X)
    77  		buf.WriteByte('[')
    78  		writeExprList(buf, ix.Indices)
    79  		buf.WriteByte(']')
    80  
    81  	case *ast.SliceExpr:
    82  		WriteExpr(buf, x.X)
    83  		buf.WriteByte('[')
    84  		if x.Low != nil {
    85  			WriteExpr(buf, x.Low)
    86  		}
    87  		buf.WriteByte(':')
    88  		if x.High != nil {
    89  			WriteExpr(buf, x.High)
    90  		}
    91  		if x.Slice3 {
    92  			buf.WriteByte(':')
    93  			if x.Max != nil {
    94  				WriteExpr(buf, x.Max)
    95  			}
    96  		}
    97  		buf.WriteByte(']')
    98  
    99  	case *ast.TypeAssertExpr:
   100  		WriteExpr(buf, x.X)
   101  		buf.WriteString(".(")
   102  		WriteExpr(buf, x.Type)
   103  		buf.WriteByte(')')
   104  
   105  	case *ast.CallExpr:
   106  		WriteExpr(buf, x.Fun)
   107  		buf.WriteByte('(')
   108  		writeExprList(buf, x.Args)
   109  		if x.Ellipsis.IsValid() {
   110  			buf.WriteString("...")
   111  		}
   112  		buf.WriteByte(')')
   113  
   114  	case *ast.StarExpr:
   115  		buf.WriteByte('*')
   116  		WriteExpr(buf, x.X)
   117  
   118  	case *ast.UnaryExpr:
   119  		buf.WriteString(x.Op.String())
   120  		WriteExpr(buf, x.X)
   121  
   122  	case *ast.BinaryExpr:
   123  		WriteExpr(buf, x.X)
   124  		buf.WriteByte(' ')
   125  		buf.WriteString(x.Op.String())
   126  		buf.WriteByte(' ')
   127  		WriteExpr(buf, x.Y)
   128  
   129  	case *ast.ArrayType:
   130  		buf.WriteByte('[')
   131  		if x.Len != nil {
   132  			WriteExpr(buf, x.Len)
   133  		}
   134  		buf.WriteByte(']')
   135  		WriteExpr(buf, x.Elt)
   136  
   137  	case *ast.StructType:
   138  		buf.WriteString("struct{")
   139  		writeFieldList(buf, x.Fields.List, "; ", false)
   140  		buf.WriteByte('}')
   141  
   142  	case *ast.FuncType:
   143  		buf.WriteString("func")
   144  		writeSigExpr(buf, x)
   145  
   146  	case *ast.InterfaceType:
   147  		buf.WriteString("interface{")
   148  		writeFieldList(buf, x.Methods.List, "; ", true)
   149  		buf.WriteByte('}')
   150  
   151  	case *ast.MapType:
   152  		buf.WriteString("map[")
   153  		WriteExpr(buf, x.Key)
   154  		buf.WriteByte(']')
   155  		WriteExpr(buf, x.Value)
   156  
   157  	case *ast.ChanType:
   158  		var s string
   159  		switch x.Dir {
   160  		case ast.SEND:
   161  			s = "chan<- "
   162  		case ast.RECV:
   163  			s = "<-chan "
   164  		default:
   165  			s = "chan "
   166  		}
   167  		buf.WriteString(s)
   168  		WriteExpr(buf, x.Value)
   169  	}
   170  }
   171  
   172  func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
   173  	buf.WriteByte('(')
   174  	writeFieldList(buf, sig.Params.List, ", ", false)
   175  	buf.WriteByte(')')
   176  
   177  	res := sig.Results
   178  	n := res.NumFields()
   179  	if n == 0 {
   180  		// no result
   181  		return
   182  	}
   183  
   184  	buf.WriteByte(' ')
   185  	if n == 1 && len(res.List[0].Names) == 0 {
   186  		// single unnamed result
   187  		WriteExpr(buf, res.List[0].Type)
   188  		return
   189  	}
   190  
   191  	// multiple or named result(s)
   192  	buf.WriteByte('(')
   193  	writeFieldList(buf, res.List, ", ", false)
   194  	buf.WriteByte(')')
   195  }
   196  
   197  func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) {
   198  	for i, f := range list {
   199  		if i > 0 {
   200  			buf.WriteString(sep)
   201  		}
   202  
   203  		// field list names
   204  		writeIdentList(buf, f.Names)
   205  
   206  		// types of interface methods consist of signatures only
   207  		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
   208  			writeSigExpr(buf, sig)
   209  			continue
   210  		}
   211  
   212  		// named fields are separated with a blank from the field type
   213  		if len(f.Names) > 0 {
   214  			buf.WriteByte(' ')
   215  		}
   216  
   217  		WriteExpr(buf, f.Type)
   218  
   219  		// ignore tag
   220  	}
   221  }
   222  
   223  func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
   224  	for i, x := range list {
   225  		if i > 0 {
   226  			buf.WriteString(", ")
   227  		}
   228  		buf.WriteString(x.Name)
   229  	}
   230  }
   231  
   232  func writeExprList(buf *bytes.Buffer, list []ast.Expr) {
   233  	for i, x := range list {
   234  		if i > 0 {
   235  			buf.WriteString(", ")
   236  		}
   237  		WriteExpr(buf, x)
   238  	}
   239  }