Home | History | Annotate | Download | only in gc
      1 // Copyright 2011 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 package gc
      6 
      7 import (
      8 	"bytes"
      9 	"cmd/internal/obj"
     10 	"fmt"
     11 	"strconv"
     12 	"strings"
     13 	"unicode/utf8"
     14 )
     15 
     16 //
     17 // Format conversions
     18 //	%L int		Line numbers
     19 //
     20 //	%E int		etype values (aka 'Kind')
     21 //
     22 //	%O int		Node Opcodes
     23 //		Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
     24 //
     25 //	%J Node*	Node details
     26 //		Flags: "%hJ" suppresses things not relevant until walk.
     27 //
     28 //	%V Val*		Constant values
     29 //
     30 //	%S Sym*		Symbols
     31 //		Flags: +,- #: mode (see below)
     32 //			"%hS"	unqualified identifier in any mode
     33 //			"%hhS"  in export mode: unqualified identifier if exported, qualified if not
     34 //
     35 //	%T Type*	Types
     36 //		Flags: +,- #: mode (see below)
     37 //			'l' definition instead of name.
     38 //			'h' omit "func" and receiver in function types
     39 //			'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
     40 //
     41 //	%N Node*	Nodes
     42 //		Flags: +,- #: mode (see below)
     43 //			'h' (only in +/debug mode) suppress recursion
     44 //			'l' (only in Error mode) print "foo (type Bar)"
     45 //
     46 //	%H NodeList*	NodeLists
     47 //		Flags: those of %N
     48 //			','  separate items with ',' instead of ';'
     49 //
     50 //   In mparith1.c:
     51 //      %B Mpint*	Big integers
     52 //	%F Mpflt*	Big floats
     53 //
     54 //   %S, %T and %N obey use the following flags to set the format mode:
     55 const (
     56 	FErr = iota
     57 	FDbg
     58 	FExp
     59 	FTypeId
     60 )
     61 
     62 var fmtmode int = FErr
     63 
     64 var fmtpkgpfx int // %uT stickyness
     65 
     66 //
     67 // E.g. for %S:	%+S %#S %-S	print an identifier properly qualified for debug/export/internal mode.
     68 //
     69 // The mode flags  +, - and # are sticky, meaning they persist through
     70 // recursions of %N, %T and %S, but not the h and l flags.  The u flag is
     71 // sticky only on %T recursions and only used in %-/Sym mode.
     72 
     73 //
     74 // Useful format combinations:
     75 //
     76 //	%+N   %+H	multiline recursive debug dump of node/nodelist
     77 //	%+hN  %+hH	non recursive debug dump
     78 //
     79 //	%#N   %#T	export format
     80 //	%#lT		type definition instead of name
     81 //	%#hT		omit"func" and receiver in function signature
     82 //
     83 //	%lN		"foo (type Bar)" for error messages
     84 //
     85 //	%-T		type identifiers
     86 //	%-hT		type identifiers without "func" and arg names in type signatures (methodsym)
     87 //	%-uT		type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
     88 //
     89 
     90 func setfmode(flags *int) int {
     91 	fm := fmtmode
     92 	if *flags&obj.FmtSign != 0 {
     93 		fmtmode = FDbg
     94 	} else if *flags&obj.FmtSharp != 0 {
     95 		fmtmode = FExp
     96 	} else if *flags&obj.FmtLeft != 0 {
     97 		fmtmode = FTypeId
     98 	}
     99 
    100 	*flags &^= (obj.FmtSharp | obj.FmtLeft | obj.FmtSign)
    101 	return fm
    102 }
    103 
    104 // Fmt "%L": Linenumbers
    105 
    106 var goopnames = []string{
    107 	OADDR:     "&",
    108 	OADD:      "+",
    109 	OADDSTR:   "+",
    110 	OANDAND:   "&&",
    111 	OANDNOT:   "&^",
    112 	OAND:      "&",
    113 	OAPPEND:   "append",
    114 	OAS:       "=",
    115 	OAS2:      "=",
    116 	OBREAK:    "break",
    117 	OCALL:     "function call", // not actual syntax
    118 	OCAP:      "cap",
    119 	OCASE:     "case",
    120 	OCLOSE:    "close",
    121 	OCOMPLEX:  "complex",
    122 	OCOM:      "^",
    123 	OCONTINUE: "continue",
    124 	OCOPY:     "copy",
    125 	ODEC:      "--",
    126 	ODELETE:   "delete",
    127 	ODEFER:    "defer",
    128 	ODIV:      "/",
    129 	OEQ:       "==",
    130 	OFALL:     "fallthrough",
    131 	OFOR:      "for",
    132 	OGE:       ">=",
    133 	OGOTO:     "goto",
    134 	OGT:       ">",
    135 	OIF:       "if",
    136 	OIMAG:     "imag",
    137 	OINC:      "++",
    138 	OIND:      "*",
    139 	OLEN:      "len",
    140 	OLE:       "<=",
    141 	OLSH:      "<<",
    142 	OLT:       "<",
    143 	OMAKE:     "make",
    144 	OMINUS:    "-",
    145 	OMOD:      "%",
    146 	OMUL:      "*",
    147 	ONEW:      "new",
    148 	ONE:       "!=",
    149 	ONOT:      "!",
    150 	OOROR:     "||",
    151 	OOR:       "|",
    152 	OPANIC:    "panic",
    153 	OPLUS:     "+",
    154 	OPRINTN:   "println",
    155 	OPRINT:    "print",
    156 	ORANGE:    "range",
    157 	OREAL:     "real",
    158 	ORECV:     "<-",
    159 	ORECOVER:  "recover",
    160 	ORETURN:   "return",
    161 	ORSH:      ">>",
    162 	OSELECT:   "select",
    163 	OSEND:     "<-",
    164 	OSUB:      "-",
    165 	OSWITCH:   "switch",
    166 	OXOR:      "^",
    167 }
    168 
    169 // Fmt "%O":  Node opcodes
    170 func Oconv(o int, flag int) string {
    171 	if (flag&obj.FmtSharp != 0) || fmtmode != FDbg {
    172 		if o >= 0 && o < len(goopnames) && goopnames[o] != "" {
    173 			return goopnames[o]
    174 		}
    175 	}
    176 
    177 	if o >= 0 && o < len(opnames) && opnames[o] != "" {
    178 		return opnames[o]
    179 	}
    180 
    181 	return fmt.Sprintf("O-%d", o)
    182 }
    183 
    184 var classnames = []string{
    185 	"Pxxx",
    186 	"PEXTERN",
    187 	"PAUTO",
    188 	"PPARAM",
    189 	"PPARAMOUT",
    190 	"PPARAMREF",
    191 	"PFUNC",
    192 }
    193 
    194 // Fmt "%J": Node details.
    195 func Jconv(n *Node, flag int) string {
    196 	var buf bytes.Buffer
    197 
    198 	c := flag & obj.FmtShort
    199 
    200 	if c == 0 && n.Ullman != 0 {
    201 		fmt.Fprintf(&buf, " u(%d)", n.Ullman)
    202 	}
    203 
    204 	if c == 0 && n.Addable {
    205 		fmt.Fprintf(&buf, " a(%v)", n.Addable)
    206 	}
    207 
    208 	if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
    209 		fmt.Fprintf(&buf, " g(%d)", n.Name.Vargen)
    210 	}
    211 
    212 	if n.Lineno != 0 {
    213 		fmt.Fprintf(&buf, " l(%d)", n.Lineno)
    214 	}
    215 
    216 	if c == 0 && n.Xoffset != BADWIDTH {
    217 		fmt.Fprintf(&buf, " x(%d%+d)", n.Xoffset, stkdelta[n])
    218 	}
    219 
    220 	if n.Class != 0 {
    221 		s := ""
    222 		if n.Class&PHEAP != 0 {
    223 			s = ",heap"
    224 		}
    225 		if int(n.Class&^PHEAP) < len(classnames) {
    226 			fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s)
    227 		} else {
    228 			fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
    229 		}
    230 	}
    231 
    232 	if n.Colas {
    233 		fmt.Fprintf(&buf, " colas(%v)", n.Colas)
    234 	}
    235 
    236 	if n.Name != nil && n.Name.Funcdepth != 0 {
    237 		fmt.Fprintf(&buf, " f(%d)", n.Name.Funcdepth)
    238 	}
    239 	if n.Func != nil && n.Func.Depth != 0 {
    240 		fmt.Fprintf(&buf, " ff(%d)", n.Func.Depth)
    241 	}
    242 
    243 	switch n.Esc {
    244 	case EscUnknown:
    245 		break
    246 
    247 	case EscHeap:
    248 		buf.WriteString(" esc(h)")
    249 
    250 	case EscScope:
    251 		buf.WriteString(" esc(s)")
    252 
    253 	case EscNone:
    254 		buf.WriteString(" esc(no)")
    255 
    256 	case EscNever:
    257 		if c == 0 {
    258 			buf.WriteString(" esc(N)")
    259 		}
    260 
    261 	default:
    262 		fmt.Fprintf(&buf, " esc(%d)", n.Esc)
    263 	}
    264 
    265 	if e, ok := n.Opt().(*NodeEscState); ok && e.Escloopdepth != 0 {
    266 		fmt.Fprintf(&buf, " ld(%d)", e.Escloopdepth)
    267 	}
    268 
    269 	if c == 0 && n.Typecheck != 0 {
    270 		fmt.Fprintf(&buf, " tc(%d)", n.Typecheck)
    271 	}
    272 
    273 	if c == 0 && n.Dodata != 0 {
    274 		fmt.Fprintf(&buf, " dd(%d)", n.Dodata)
    275 	}
    276 
    277 	if n.Isddd {
    278 		fmt.Fprintf(&buf, " isddd(%v)", n.Isddd)
    279 	}
    280 
    281 	if n.Implicit {
    282 		fmt.Fprintf(&buf, " implicit(%v)", n.Implicit)
    283 	}
    284 
    285 	if n.Embedded != 0 {
    286 		fmt.Fprintf(&buf, " embedded(%d)", n.Embedded)
    287 	}
    288 
    289 	if n.Addrtaken {
    290 		buf.WriteString(" addrtaken")
    291 	}
    292 
    293 	if n.Assigned {
    294 		buf.WriteString(" assigned")
    295 	}
    296 
    297 	if c == 0 && n.Used {
    298 		fmt.Fprintf(&buf, " used(%v)", n.Used)
    299 	}
    300 	return buf.String()
    301 }
    302 
    303 // Fmt "%V": Values
    304 func Vconv(v Val, flag int) string {
    305 	switch v.Ctype() {
    306 	case CTINT:
    307 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
    308 			return Bconv(v.U.(*Mpint), obj.FmtSharp)
    309 		}
    310 		return Bconv(v.U.(*Mpint), 0)
    311 
    312 	case CTRUNE:
    313 		x := Mpgetfix(v.U.(*Mpint))
    314 		if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
    315 			return fmt.Sprintf("'%c'", int(x))
    316 		}
    317 		if 0 <= x && x < 1<<16 {
    318 			return fmt.Sprintf("'\\u%04x'", uint(int(x)))
    319 		}
    320 		if 0 <= x && x <= utf8.MaxRune {
    321 			return fmt.Sprintf("'\\U%08x'", uint64(x))
    322 		}
    323 		return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
    324 
    325 	case CTFLT:
    326 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
    327 			return Fconv(v.U.(*Mpflt), 0)
    328 		}
    329 		return Fconv(v.U.(*Mpflt), obj.FmtSharp)
    330 
    331 	case CTCPLX:
    332 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
    333 			return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
    334 		}
    335 		if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 {
    336 			return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
    337 		}
    338 		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 {
    339 			return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp)
    340 		}
    341 		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 {
    342 			return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
    343 		}
    344 		return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
    345 
    346 	case CTSTR:
    347 		return strconv.Quote(v.U.(string))
    348 
    349 	case CTBOOL:
    350 		if v.U.(bool) {
    351 			return "true"
    352 		}
    353 		return "false"
    354 
    355 	case CTNIL:
    356 		return "nil"
    357 	}
    358 
    359 	return fmt.Sprintf("<ctype=%d>", v.Ctype)
    360 }
    361 
    362 /*
    363 s%,%,\n%g
    364 s%\n+%\n%g
    365 s%^[	]*T%%g
    366 s%,.*%%g
    367 s%.+%	[T&]		= "&",%g
    368 s%^	........*\]%&~%g
    369 s%~	%%g
    370 */
    371 var etnames = []string{
    372 	TINT:        "INT",
    373 	TUINT:       "UINT",
    374 	TINT8:       "INT8",
    375 	TUINT8:      "UINT8",
    376 	TINT16:      "INT16",
    377 	TUINT16:     "UINT16",
    378 	TINT32:      "INT32",
    379 	TUINT32:     "UINT32",
    380 	TINT64:      "INT64",
    381 	TUINT64:     "UINT64",
    382 	TUINTPTR:    "UINTPTR",
    383 	TFLOAT32:    "FLOAT32",
    384 	TFLOAT64:    "FLOAT64",
    385 	TCOMPLEX64:  "COMPLEX64",
    386 	TCOMPLEX128: "COMPLEX128",
    387 	TBOOL:       "BOOL",
    388 	TPTR32:      "PTR32",
    389 	TPTR64:      "PTR64",
    390 	TFUNC:       "FUNC",
    391 	TARRAY:      "ARRAY",
    392 	TSTRUCT:     "STRUCT",
    393 	TCHAN:       "CHAN",
    394 	TMAP:        "MAP",
    395 	TINTER:      "INTER",
    396 	TFORW:       "FORW",
    397 	TFIELD:      "FIELD",
    398 	TSTRING:     "STRING",
    399 	TANY:        "ANY",
    400 }
    401 
    402 // Fmt "%E": etype
    403 func Econv(et int, flag int) string {
    404 	if et >= 0 && et < len(etnames) && etnames[et] != "" {
    405 		return etnames[et]
    406 	}
    407 	return fmt.Sprintf("E-%d", et)
    408 }
    409 
    410 // Fmt "%S": syms
    411 func symfmt(s *Sym, flag int) string {
    412 	if s.Pkg != nil && flag&obj.FmtShort == 0 {
    413 		switch fmtmode {
    414 		case FErr: // This is for the user
    415 			if s.Pkg == localpkg {
    416 				return s.Name
    417 			}
    418 
    419 			// If the name was used by multiple packages, display the full path,
    420 			if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
    421 				return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
    422 			}
    423 			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
    424 
    425 		case FDbg:
    426 			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
    427 
    428 		case FTypeId:
    429 			if flag&obj.FmtUnsigned != 0 {
    430 				return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name) // dcommontype, typehash
    431 			}
    432 			return fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name) // (methodsym), typesym, weaksym
    433 
    434 		case FExp:
    435 			if s.Name != "" && s.Name[0] == '.' {
    436 				Fatal("exporting synthetic symbol %s", s.Name)
    437 			}
    438 			if s.Pkg != builtinpkg {
    439 				return fmt.Sprintf("@%q.%s", s.Pkg.Path, s.Name)
    440 			}
    441 		}
    442 	}
    443 
    444 	if flag&obj.FmtByte != 0 {
    445 		// FmtByte (hh) implies FmtShort (h)
    446 		// skip leading "type." in method name
    447 		p := s.Name
    448 		if i := strings.LastIndex(s.Name, "."); i >= 0 {
    449 			p = s.Name[i+1:]
    450 		}
    451 
    452 		// exportname needs to see the name without the prefix too.
    453 		if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
    454 			return fmt.Sprintf("@%q.%s", s.Pkg.Path, p)
    455 		}
    456 
    457 		return p
    458 	}
    459 
    460 	return s.Name
    461 }
    462 
    463 var basicnames = []string{
    464 	TINT:        "int",
    465 	TUINT:       "uint",
    466 	TINT8:       "int8",
    467 	TUINT8:      "uint8",
    468 	TINT16:      "int16",
    469 	TUINT16:     "uint16",
    470 	TINT32:      "int32",
    471 	TUINT32:     "uint32",
    472 	TINT64:      "int64",
    473 	TUINT64:     "uint64",
    474 	TUINTPTR:    "uintptr",
    475 	TFLOAT32:    "float32",
    476 	TFLOAT64:    "float64",
    477 	TCOMPLEX64:  "complex64",
    478 	TCOMPLEX128: "complex128",
    479 	TBOOL:       "bool",
    480 	TANY:        "any",
    481 	TSTRING:     "string",
    482 	TNIL:        "nil",
    483 	TIDEAL:      "untyped number",
    484 	TBLANK:      "blank",
    485 }
    486 
    487 func typefmt(t *Type, flag int) string {
    488 	if t == nil {
    489 		return "<T>"
    490 	}
    491 
    492 	if t == bytetype || t == runetype {
    493 		// in %-T mode collapse rune and byte with their originals.
    494 		if fmtmode != FTypeId {
    495 			return Sconv(t.Sym, obj.FmtShort)
    496 		}
    497 		t = Types[t.Etype]
    498 	}
    499 
    500 	if t == errortype {
    501 		return "error"
    502 	}
    503 
    504 	// Unless the 'l' flag was specified, if the type has a name, just print that name.
    505 	if flag&obj.FmtLong == 0 && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] {
    506 		switch fmtmode {
    507 		case FTypeId:
    508 			if flag&obj.FmtShort != 0 {
    509 				if t.Vargen != 0 {
    510 					return fmt.Sprintf("%v%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
    511 				}
    512 				return Sconv(t.Sym, obj.FmtShort)
    513 			}
    514 
    515 			if flag&obj.FmtUnsigned != 0 {
    516 				return Sconv(t.Sym, obj.FmtUnsigned)
    517 			}
    518 			fallthrough
    519 
    520 		case FExp:
    521 			if t.Sym.Pkg == localpkg && t.Vargen != 0 {
    522 				return fmt.Sprintf("%v%d", t.Sym, t.Vargen)
    523 			}
    524 		}
    525 
    526 		return Sconv(t.Sym, 0)
    527 	}
    528 
    529 	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
    530 		prefix := ""
    531 		if fmtmode == FErr && (t == idealbool || t == idealstring) {
    532 			prefix = "untyped "
    533 		}
    534 		return prefix + basicnames[t.Etype]
    535 	}
    536 
    537 	if fmtmode == FDbg {
    538 		fmtmode = 0
    539 		str := Econv(int(t.Etype), 0) + "-" + typefmt(t, flag)
    540 		fmtmode = FDbg
    541 		return str
    542 	}
    543 
    544 	switch t.Etype {
    545 	case TPTR32, TPTR64:
    546 		if fmtmode == FTypeId && (flag&obj.FmtShort != 0) {
    547 			return fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
    548 		}
    549 		return fmt.Sprintf("*%v", t.Type)
    550 
    551 	case TARRAY:
    552 		if t.Bound >= 0 {
    553 			return fmt.Sprintf("[%d]%v", t.Bound, t.Type)
    554 		}
    555 		if t.Bound == -100 {
    556 			return fmt.Sprintf("[...]%v", t.Type)
    557 		}
    558 		return fmt.Sprintf("[]%v", t.Type)
    559 
    560 	case TCHAN:
    561 		switch t.Chan {
    562 		case Crecv:
    563 			return fmt.Sprintf("<-chan %v", t.Type)
    564 
    565 		case Csend:
    566 			return fmt.Sprintf("chan<- %v", t.Type)
    567 		}
    568 
    569 		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
    570 			return fmt.Sprintf("chan (%v)", t.Type)
    571 		}
    572 		return fmt.Sprintf("chan %v", t.Type)
    573 
    574 	case TMAP:
    575 		return fmt.Sprintf("map[%v]%v", t.Down, t.Type)
    576 
    577 	case TINTER:
    578 		var buf bytes.Buffer
    579 		buf.WriteString("interface {")
    580 		for t1 := t.Type; t1 != nil; t1 = t1.Down {
    581 			buf.WriteString(" ")
    582 			if exportname(t1.Sym.Name) {
    583 				buf.WriteString(Sconv(t1.Sym, obj.FmtShort))
    584 			} else {
    585 				buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned))
    586 			}
    587 			buf.WriteString(Tconv(t1.Type, obj.FmtShort))
    588 			if t1.Down != nil {
    589 				buf.WriteString(";")
    590 			}
    591 		}
    592 		if t.Type != nil {
    593 			buf.WriteString(" ")
    594 		}
    595 		buf.WriteString("}")
    596 		return buf.String()
    597 
    598 	case TFUNC:
    599 		var buf bytes.Buffer
    600 		if flag&obj.FmtShort != 0 {
    601 			// no leading func
    602 		} else {
    603 			if t.Thistuple != 0 {
    604 				buf.WriteString("method")
    605 				buf.WriteString(Tconv(getthisx(t), 0))
    606 				buf.WriteString(" ")
    607 			}
    608 			buf.WriteString("func")
    609 		}
    610 		buf.WriteString(Tconv(getinargx(t), 0))
    611 
    612 		switch t.Outtuple {
    613 		case 0:
    614 			break
    615 
    616 		case 1:
    617 			if fmtmode != FExp {
    618 				buf.WriteString(" ")
    619 				buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
    620 				break
    621 			}
    622 			fallthrough
    623 
    624 		default:
    625 			buf.WriteString(" ")
    626 			buf.WriteString(Tconv(getoutargx(t), 0))
    627 		}
    628 		return buf.String()
    629 
    630 	case TSTRUCT:
    631 		if t.Map != nil {
    632 			// Format the bucket struct for map[x]y as map.bucket[x]y.
    633 			// This avoids a recursive print that generates very long names.
    634 			if t.Map.Bucket == t {
    635 				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
    636 			}
    637 
    638 			if t.Map.Hmap == t {
    639 				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
    640 			}
    641 
    642 			if t.Map.Hiter == t {
    643 				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
    644 			}
    645 
    646 			Yyerror("unknown internal map type")
    647 		}
    648 
    649 		var buf bytes.Buffer
    650 		if t.Funarg != 0 {
    651 			buf.WriteString("(")
    652 			if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
    653 				for t1 := t.Type; t1 != nil; t1 = t1.Down {
    654 					buf.WriteString(Tconv(t1, obj.FmtShort))
    655 					if t1.Down != nil {
    656 						buf.WriteString(", ")
    657 					}
    658 				}
    659 			} else {
    660 				for t1 := t.Type; t1 != nil; t1 = t1.Down {
    661 					buf.WriteString(Tconv(t1, 0))
    662 					if t1.Down != nil {
    663 						buf.WriteString(", ")
    664 					}
    665 				}
    666 			}
    667 			buf.WriteString(")")
    668 		} else {
    669 			buf.WriteString("struct {")
    670 			for t1 := t.Type; t1 != nil; t1 = t1.Down {
    671 				buf.WriteString(" ")
    672 				buf.WriteString(Tconv(t1, obj.FmtLong))
    673 				if t1.Down != nil {
    674 					buf.WriteString(";")
    675 				}
    676 			}
    677 			if t.Type != nil {
    678 				buf.WriteString(" ")
    679 			}
    680 			buf.WriteString("}")
    681 		}
    682 		return buf.String()
    683 
    684 	case TFIELD:
    685 		var name string
    686 		if flag&obj.FmtShort == 0 {
    687 			s := t.Sym
    688 
    689 			// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
    690 			// ~r%d is a (formerly) unnamed result.
    691 			if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil {
    692 				if t.Nname.Orig != nil {
    693 					s = t.Nname.Orig.Sym
    694 					if s != nil && s.Name[0] == '~' {
    695 						if s.Name[1] == 'r' { // originally an unnamed result
    696 							s = nil
    697 						} else if s.Name[1] == 'b' { // originally the blank identifier _
    698 							s = Lookup("_")
    699 						}
    700 					}
    701 				} else {
    702 					s = nil
    703 				}
    704 			}
    705 
    706 			if s != nil && t.Embedded == 0 {
    707 				if t.Funarg != 0 {
    708 					name = Nconv(t.Nname, 0)
    709 				} else if flag&obj.FmtLong != 0 {
    710 					name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg)
    711 				} else {
    712 					name = Sconv(s, 0)
    713 				}
    714 			} else if fmtmode == FExp {
    715 				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
    716 				// when this is fixed, the special case in dcl.c checkarglist can go.
    717 				//if(t->funarg)
    718 				//	fmtstrcpy(fp, "_ ");
    719 				//else
    720 				if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
    721 					name = fmt.Sprintf("@%q.?", s.Pkg.Path)
    722 				} else {
    723 					name = "?"
    724 				}
    725 			}
    726 		}
    727 
    728 		var typ string
    729 		if t.Isddd {
    730 			typ = "..." + Tconv(t.Type.Type, 0)
    731 		} else {
    732 			typ = Tconv(t.Type, 0)
    733 		}
    734 
    735 		str := typ
    736 		if name != "" {
    737 			str = name + " " + typ
    738 		}
    739 		if flag&obj.FmtShort == 0 && t.Note != nil {
    740 			str += " " + strconv.Quote(*t.Note)
    741 		}
    742 		return str
    743 
    744 	case TFORW:
    745 		if t.Sym != nil {
    746 			return fmt.Sprintf("undefined %v", t.Sym)
    747 		}
    748 		return "undefined"
    749 
    750 	case TUNSAFEPTR:
    751 		if fmtmode == FExp {
    752 			return "@\"unsafe\".Pointer"
    753 		}
    754 		return "unsafe.Pointer"
    755 	}
    756 
    757 	if fmtmode == FExp {
    758 		Fatal("missing %v case during export", Econv(int(t.Etype), 0))
    759 	}
    760 
    761 	// Don't know how to handle - fall back to detailed prints.
    762 	return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), t.Sym, t.Type)
    763 }
    764 
    765 // Statements which may be rendered with a simplestmt as init.
    766 func stmtwithinit(op int) bool {
    767 	switch op {
    768 	case OIF, OFOR, OSWITCH:
    769 		return true
    770 	}
    771 
    772 	return false
    773 }
    774 
    775 func stmtfmt(n *Node) string {
    776 	var f string
    777 
    778 	// some statements allow for an init, but at most one,
    779 	// but we may have an arbitrary number added, eg by typecheck
    780 	// and inlining.  If it doesn't fit the syntax, emit an enclosing
    781 	// block starting with the init statements.
    782 
    783 	// if we can just say "for" n->ninit; ... then do so
    784 	simpleinit := n.Ninit != nil && n.Ninit.Next == nil && n.Ninit.N.Ninit == nil && stmtwithinit(int(n.Op))
    785 
    786 	// otherwise, print the inits as separate statements
    787 	complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr)
    788 
    789 	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
    790 	extrablock := complexinit && stmtwithinit(int(n.Op))
    791 
    792 	if extrablock {
    793 		f += "{"
    794 	}
    795 
    796 	if complexinit {
    797 		f += fmt.Sprintf(" %v; ", n.Ninit)
    798 	}
    799 
    800 	switch n.Op {
    801 	case ODCL:
    802 		if fmtmode == FExp {
    803 			switch n.Left.Class &^ PHEAP {
    804 			case PPARAM, PPARAMOUT, PAUTO:
    805 				f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
    806 				goto ret
    807 			}
    808 		}
    809 
    810 		f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
    811 
    812 	case ODCLFIELD:
    813 		if n.Left != nil {
    814 			f += fmt.Sprintf("%v %v", n.Left, n.Right)
    815 		} else {
    816 			f += Nconv(n.Right, 0)
    817 		}
    818 
    819 		// Don't export "v = <N>" initializing statements, hope they're always
    820 	// preceded by the DCL which will be re-parsed and typecheck to reproduce
    821 	// the "v = <N>" again.
    822 	case OAS, OASWB:
    823 		if fmtmode == FExp && n.Right == nil {
    824 			break
    825 		}
    826 
    827 		if n.Colas && !complexinit {
    828 			f += fmt.Sprintf("%v := %v", n.Left, n.Right)
    829 		} else {
    830 			f += fmt.Sprintf("%v = %v", n.Left, n.Right)
    831 		}
    832 
    833 	case OASOP:
    834 		if n.Implicit {
    835 			if n.Etype == OADD {
    836 				f += fmt.Sprintf("%v++", n.Left)
    837 			} else {
    838 				f += fmt.Sprintf("%v--", n.Left)
    839 			}
    840 			break
    841 		}
    842 
    843 		f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right)
    844 
    845 	case OAS2:
    846 		if n.Colas && !complexinit {
    847 			f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
    848 			break
    849 		}
    850 		fallthrough
    851 
    852 	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
    853 		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
    854 
    855 	case ORETURN:
    856 		f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
    857 
    858 	case ORETJMP:
    859 		f += fmt.Sprintf("retjmp %v", n.Sym)
    860 
    861 	case OPROC:
    862 		f += fmt.Sprintf("go %v", n.Left)
    863 
    864 	case ODEFER:
    865 		f += fmt.Sprintf("defer %v", n.Left)
    866 
    867 	case OIF:
    868 		if simpleinit {
    869 			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Left, n.Nbody)
    870 		} else {
    871 			f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody)
    872 		}
    873 		if n.Rlist != nil {
    874 			f += fmt.Sprintf(" else { %v }", n.Rlist)
    875 		}
    876 
    877 	case OFOR:
    878 		if fmtmode == FErr { // TODO maybe only if FmtShort, same below
    879 			f += "for loop"
    880 			break
    881 		}
    882 
    883 		f += "for"
    884 		if simpleinit {
    885 			f += fmt.Sprintf(" %v;", n.Ninit.N)
    886 		} else if n.Right != nil {
    887 			f += " ;"
    888 		}
    889 
    890 		if n.Left != nil {
    891 			f += fmt.Sprintf(" %v", n.Left)
    892 		}
    893 
    894 		if n.Right != nil {
    895 			f += fmt.Sprintf("; %v", n.Right)
    896 		} else if simpleinit {
    897 			f += ";"
    898 		}
    899 
    900 		f += fmt.Sprintf(" { %v }", n.Nbody)
    901 
    902 	case ORANGE:
    903 		if fmtmode == FErr {
    904 			f += "for loop"
    905 			break
    906 		}
    907 
    908 		if n.List == nil {
    909 			f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody)
    910 			break
    911 		}
    912 
    913 		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), n.Right, n.Nbody)
    914 
    915 	case OSELECT, OSWITCH:
    916 		if fmtmode == FErr {
    917 			f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
    918 			break
    919 		}
    920 
    921 		f += Oconv(int(n.Op), obj.FmtSharp)
    922 		if simpleinit {
    923 			f += fmt.Sprintf(" %v;", n.Ninit.N)
    924 		}
    925 		if n.Left != nil {
    926 			f += Nconv(n.Left, 0)
    927 		}
    928 
    929 		f += fmt.Sprintf(" { %v }", n.List)
    930 
    931 	case OCASE, OXCASE:
    932 		if n.List != nil {
    933 			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), n.Nbody)
    934 		} else {
    935 			f += fmt.Sprintf("default: %v", n.Nbody)
    936 		}
    937 
    938 	case OBREAK,
    939 		OCONTINUE,
    940 		OGOTO,
    941 		OFALL,
    942 		OXFALL:
    943 		if n.Left != nil {
    944 			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left)
    945 		} else {
    946 			f += Oconv(int(n.Op), obj.FmtSharp)
    947 		}
    948 
    949 	case OEMPTY:
    950 		break
    951 
    952 	case OLABEL:
    953 		f += fmt.Sprintf("%v: ", n.Left)
    954 	}
    955 
    956 ret:
    957 	if extrablock {
    958 		f += "}"
    959 	}
    960 
    961 	return f
    962 }
    963 
    964 var opprec = []int{
    965 	OAPPEND:       8,
    966 	OARRAYBYTESTR: 8,
    967 	OARRAYLIT:     8,
    968 	OARRAYRUNESTR: 8,
    969 	OCALLFUNC:     8,
    970 	OCALLINTER:    8,
    971 	OCALLMETH:     8,
    972 	OCALL:         8,
    973 	OCAP:          8,
    974 	OCLOSE:        8,
    975 	OCONVIFACE:    8,
    976 	OCONVNOP:      8,
    977 	OCONV:         8,
    978 	OCOPY:         8,
    979 	ODELETE:       8,
    980 	OGETG:         8,
    981 	OLEN:          8,
    982 	OLITERAL:      8,
    983 	OMAKESLICE:    8,
    984 	OMAKE:         8,
    985 	OMAPLIT:       8,
    986 	ONAME:         8,
    987 	ONEW:          8,
    988 	ONONAME:       8,
    989 	OPACK:         8,
    990 	OPANIC:        8,
    991 	OPAREN:        8,
    992 	OPRINTN:       8,
    993 	OPRINT:        8,
    994 	ORUNESTR:      8,
    995 	OSTRARRAYBYTE: 8,
    996 	OSTRARRAYRUNE: 8,
    997 	OSTRUCTLIT:    8,
    998 	OTARRAY:       8,
    999 	OTCHAN:        8,
   1000 	OTFUNC:        8,
   1001 	OTINTER:       8,
   1002 	OTMAP:         8,
   1003 	OTSTRUCT:      8,
   1004 	OINDEXMAP:     8,
   1005 	OINDEX:        8,
   1006 	OSLICE:        8,
   1007 	OSLICESTR:     8,
   1008 	OSLICEARR:     8,
   1009 	OSLICE3:       8,
   1010 	OSLICE3ARR:    8,
   1011 	ODOTINTER:     8,
   1012 	ODOTMETH:      8,
   1013 	ODOTPTR:       8,
   1014 	ODOTTYPE2:     8,
   1015 	ODOTTYPE:      8,
   1016 	ODOT:          8,
   1017 	OXDOT:         8,
   1018 	OCALLPART:     8,
   1019 	OPLUS:         7,
   1020 	ONOT:          7,
   1021 	OCOM:          7,
   1022 	OMINUS:        7,
   1023 	OADDR:         7,
   1024 	OIND:          7,
   1025 	ORECV:         7,
   1026 	OMUL:          6,
   1027 	ODIV:          6,
   1028 	OMOD:          6,
   1029 	OLSH:          6,
   1030 	ORSH:          6,
   1031 	OAND:          6,
   1032 	OANDNOT:       6,
   1033 	OADD:          5,
   1034 	OSUB:          5,
   1035 	OOR:           5,
   1036 	OXOR:          5,
   1037 	OEQ:           4,
   1038 	OLT:           4,
   1039 	OLE:           4,
   1040 	OGE:           4,
   1041 	OGT:           4,
   1042 	ONE:           4,
   1043 	OCMPSTR:       4,
   1044 	OCMPIFACE:     4,
   1045 	OSEND:         3,
   1046 	OANDAND:       2,
   1047 	OOROR:         1,
   1048 	// Statements handled by stmtfmt
   1049 	OAS:         -1,
   1050 	OAS2:        -1,
   1051 	OAS2DOTTYPE: -1,
   1052 	OAS2FUNC:    -1,
   1053 	OAS2MAPR:    -1,
   1054 	OAS2RECV:    -1,
   1055 	OASOP:       -1,
   1056 	OBREAK:      -1,
   1057 	OCASE:       -1,
   1058 	OCONTINUE:   -1,
   1059 	ODCL:        -1,
   1060 	ODCLFIELD:   -1,
   1061 	ODEFER:      -1,
   1062 	OEMPTY:      -1,
   1063 	OFALL:       -1,
   1064 	OFOR:        -1,
   1065 	OGOTO:       -1,
   1066 	OIF:         -1,
   1067 	OLABEL:      -1,
   1068 	OPROC:       -1,
   1069 	ORANGE:      -1,
   1070 	ORETURN:     -1,
   1071 	OSELECT:     -1,
   1072 	OSWITCH:     -1,
   1073 	OXCASE:      -1,
   1074 	OXFALL:      -1,
   1075 	OEND:        0,
   1076 }
   1077 
   1078 func exprfmt(n *Node, prec int) string {
   1079 	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
   1080 		n = n.Left
   1081 	}
   1082 
   1083 	if n == nil {
   1084 		return "<N>"
   1085 	}
   1086 
   1087 	nprec := opprec[n.Op]
   1088 	if n.Op == OTYPE && n.Sym != nil {
   1089 		nprec = 8
   1090 	}
   1091 
   1092 	if prec > nprec {
   1093 		return fmt.Sprintf("(%v)", n)
   1094 	}
   1095 
   1096 	switch n.Op {
   1097 	case OPAREN:
   1098 		return fmt.Sprintf("(%v)", n.Left)
   1099 
   1100 	case ODDDARG:
   1101 		return "... argument"
   1102 
   1103 	case OREGISTER:
   1104 		return obj.Rconv(int(n.Reg))
   1105 
   1106 	case OLITERAL: // this is a bit of a mess
   1107 		if fmtmode == FErr {
   1108 			if n.Orig != nil && n.Orig != n {
   1109 				return exprfmt(n.Orig, prec)
   1110 			}
   1111 			if n.Sym != nil {
   1112 				return Sconv(n.Sym, 0)
   1113 			}
   1114 		}
   1115 		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
   1116 			return exprfmt(n.Orig, prec)
   1117 		}
   1118 		if n.Type != nil && n.Type != Types[n.Type.Etype] && n.Type != idealbool && n.Type != idealstring {
   1119 			// Need parens when type begins with what might
   1120 			// be misinterpreted as a unary operator: * or <-.
   1121 			if Isptr[n.Type.Etype] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
   1122 				return fmt.Sprintf("(%v)(%v)", n.Type, Vconv(n.Val(), 0))
   1123 			} else {
   1124 				return fmt.Sprintf("%v(%v)", n.Type, Vconv(n.Val(), 0))
   1125 			}
   1126 		}
   1127 
   1128 		return Vconv(n.Val(), 0)
   1129 
   1130 		// Special case: name used as local variable in export.
   1131 	// _ becomes ~b%d internally; print as _ for export
   1132 	case ONAME:
   1133 		if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
   1134 			return "_"
   1135 		}
   1136 		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
   1137 			return fmt.Sprintf("%v%d", n.Sym, n.Name.Vargen)
   1138 		}
   1139 
   1140 		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
   1141 		// but for export, this should be rendered as (*pkg.T).meth.
   1142 		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
   1143 		if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
   1144 			if Isptr[n.Left.Type.Etype] {
   1145 				return fmt.Sprintf("(%v).%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
   1146 			} else {
   1147 				return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
   1148 			}
   1149 		}
   1150 		fallthrough
   1151 
   1152 		//fallthrough
   1153 	case OPACK, ONONAME:
   1154 		return Sconv(n.Sym, 0)
   1155 
   1156 	case OTYPE:
   1157 		if n.Type == nil && n.Sym != nil {
   1158 			return Sconv(n.Sym, 0)
   1159 		}
   1160 		return Tconv(n.Type, 0)
   1161 
   1162 	case OTARRAY:
   1163 		if n.Left != nil {
   1164 			return fmt.Sprintf("[]%v", n.Left)
   1165 		}
   1166 		var f string
   1167 		f += fmt.Sprintf("[]%v", n.Right)
   1168 		return f // happens before typecheck
   1169 
   1170 	case OTMAP:
   1171 		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
   1172 
   1173 	case OTCHAN:
   1174 		switch n.Etype {
   1175 		case Crecv:
   1176 			return fmt.Sprintf("<-chan %v", n.Left)
   1177 
   1178 		case Csend:
   1179 			return fmt.Sprintf("chan<- %v", n.Left)
   1180 
   1181 		default:
   1182 			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
   1183 				return fmt.Sprintf("chan (%v)", n.Left)
   1184 			} else {
   1185 				return fmt.Sprintf("chan %v", n.Left)
   1186 			}
   1187 		}
   1188 
   1189 	case OTSTRUCT:
   1190 		return "<struct>"
   1191 
   1192 	case OTINTER:
   1193 		return "<inter>"
   1194 
   1195 	case OTFUNC:
   1196 		return "<func>"
   1197 
   1198 	case OCLOSURE:
   1199 		if fmtmode == FErr {
   1200 			return "func literal"
   1201 		}
   1202 		if n.Nbody != nil {
   1203 			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
   1204 		}
   1205 		return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
   1206 
   1207 	case OCOMPLIT:
   1208 		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
   1209 		if fmtmode == FErr {
   1210 			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
   1211 				if ptrlit {
   1212 					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
   1213 				} else {
   1214 					return fmt.Sprintf("%v literal", n.Right.Type)
   1215 				}
   1216 			}
   1217 
   1218 			return "composite literal"
   1219 		}
   1220 
   1221 		if fmtmode == FExp && ptrlit {
   1222 			// typecheck has overwritten OIND by OTYPE with pointer type.
   1223 			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, obj.FmtComma))
   1224 		}
   1225 
   1226 		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma))
   1227 
   1228 	case OPTRLIT:
   1229 		if fmtmode == FExp && n.Left.Implicit {
   1230 			return Nconv(n.Left, 0)
   1231 		}
   1232 		return fmt.Sprintf("&%v", n.Left)
   1233 
   1234 	case OSTRUCTLIT:
   1235 		if fmtmode == FExp { // requires special handling of field names
   1236 			var f string
   1237 			if n.Implicit {
   1238 				f += "{"
   1239 			} else {
   1240 				f += fmt.Sprintf("(%v{", n.Type)
   1241 			}
   1242 			for l := n.List; l != nil; l = l.Next {
   1243 				f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), l.N.Right)
   1244 
   1245 				if l.Next != nil {
   1246 					f += ","
   1247 				} else {
   1248 					f += " "
   1249 				}
   1250 			}
   1251 
   1252 			if !n.Implicit {
   1253 				f += "})"
   1254 				return f
   1255 			}
   1256 			f += "}"
   1257 			return f
   1258 		}
   1259 		fallthrough
   1260 
   1261 	case OARRAYLIT, OMAPLIT:
   1262 		if fmtmode == FErr {
   1263 			return fmt.Sprintf("%v literal", n.Type)
   1264 		}
   1265 		if fmtmode == FExp && n.Implicit {
   1266 			return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
   1267 		}
   1268 		return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma))
   1269 
   1270 	case OKEY:
   1271 		if n.Left != nil && n.Right != nil {
   1272 			if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
   1273 				// requires special handling of field names
   1274 				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right)
   1275 			} else {
   1276 				return fmt.Sprintf("%v:%v", n.Left, n.Right)
   1277 			}
   1278 		}
   1279 
   1280 		if n.Left == nil && n.Right != nil {
   1281 			return fmt.Sprintf(":%v", n.Right)
   1282 		}
   1283 		if n.Left != nil && n.Right == nil {
   1284 			return fmt.Sprintf("%v:", n.Left)
   1285 		}
   1286 		return ":"
   1287 
   1288 	case OXDOT,
   1289 		ODOT,
   1290 		ODOTPTR,
   1291 		ODOTINTER,
   1292 		ODOTMETH,
   1293 		OCALLPART:
   1294 		var f string
   1295 		f += exprfmt(n.Left, nprec)
   1296 		if n.Right == nil || n.Right.Sym == nil {
   1297 			f += ".<nil>"
   1298 			return f
   1299 		}
   1300 		f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
   1301 		return f
   1302 
   1303 	case ODOTTYPE, ODOTTYPE2:
   1304 		var f string
   1305 		f += exprfmt(n.Left, nprec)
   1306 		if n.Right != nil {
   1307 			f += fmt.Sprintf(".(%v)", n.Right)
   1308 			return f
   1309 		}
   1310 		f += fmt.Sprintf(".(%v)", n.Type)
   1311 		return f
   1312 
   1313 	case OINDEX,
   1314 		OINDEXMAP,
   1315 		OSLICE,
   1316 		OSLICESTR,
   1317 		OSLICEARR,
   1318 		OSLICE3,
   1319 		OSLICE3ARR:
   1320 		var f string
   1321 		f += exprfmt(n.Left, nprec)
   1322 		f += fmt.Sprintf("[%v]", n.Right)
   1323 		return f
   1324 
   1325 	case OCOPY, OCOMPLEX:
   1326 		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right)
   1327 
   1328 	case OCONV,
   1329 		OCONVIFACE,
   1330 		OCONVNOP,
   1331 		OARRAYBYTESTR,
   1332 		OARRAYRUNESTR,
   1333 		OSTRARRAYBYTE,
   1334 		OSTRARRAYRUNE,
   1335 		ORUNESTR:
   1336 		if n.Type == nil || n.Type.Sym == nil {
   1337 			return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
   1338 		}
   1339 		if n.Left != nil {
   1340 			return fmt.Sprintf("%v(%v)", n.Type, n.Left)
   1341 		}
   1342 		return fmt.Sprintf("%v(%v)", n.Type, Hconv(n.List, obj.FmtComma))
   1343 
   1344 	case OREAL,
   1345 		OIMAG,
   1346 		OAPPEND,
   1347 		OCAP,
   1348 		OCLOSE,
   1349 		ODELETE,
   1350 		OLEN,
   1351 		OMAKE,
   1352 		ONEW,
   1353 		OPANIC,
   1354 		ORECOVER,
   1355 		OPRINT,
   1356 		OPRINTN:
   1357 		if n.Left != nil {
   1358 			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left)
   1359 		}
   1360 		if n.Isddd {
   1361 			return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
   1362 		}
   1363 		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
   1364 
   1365 	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
   1366 		var f string
   1367 		f += exprfmt(n.Left, nprec)
   1368 		if n.Isddd {
   1369 			f += fmt.Sprintf("(%v...)", Hconv(n.List, obj.FmtComma))
   1370 			return f
   1371 		}
   1372 		f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma))
   1373 		return f
   1374 
   1375 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
   1376 		if n.List != nil { // pre-typecheck
   1377 			return fmt.Sprintf("make(%v, %v)", n.Type, Hconv(n.List, obj.FmtComma))
   1378 		}
   1379 		if n.Right != nil {
   1380 			return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
   1381 		}
   1382 		if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) {
   1383 			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
   1384 		}
   1385 		return fmt.Sprintf("make(%v)", n.Type)
   1386 
   1387 		// Unary
   1388 	case OPLUS,
   1389 		OMINUS,
   1390 		OADDR,
   1391 		OCOM,
   1392 		OIND,
   1393 		ONOT,
   1394 		ORECV:
   1395 		var f string
   1396 		if n.Left.Op == n.Op {
   1397 			f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp))
   1398 		} else {
   1399 			f += Oconv(int(n.Op), obj.FmtSharp)
   1400 		}
   1401 		f += exprfmt(n.Left, nprec+1)
   1402 		return f
   1403 
   1404 		// Binary
   1405 	case OADD,
   1406 		OAND,
   1407 		OANDAND,
   1408 		OANDNOT,
   1409 		ODIV,
   1410 		OEQ,
   1411 		OGE,
   1412 		OGT,
   1413 		OLE,
   1414 		OLT,
   1415 		OLSH,
   1416 		OMOD,
   1417 		OMUL,
   1418 		ONE,
   1419 		OOR,
   1420 		OOROR,
   1421 		ORSH,
   1422 		OSEND,
   1423 		OSUB,
   1424 		OXOR:
   1425 		var f string
   1426 		f += exprfmt(n.Left, nprec)
   1427 
   1428 		f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp))
   1429 		f += exprfmt(n.Right, nprec+1)
   1430 		return f
   1431 
   1432 	case OADDSTR:
   1433 		var f string
   1434 		for l := n.List; l != nil; l = l.Next {
   1435 			if l != n.List {
   1436 				f += " + "
   1437 			}
   1438 			f += exprfmt(l.N, nprec)
   1439 		}
   1440 
   1441 		return f
   1442 
   1443 	case OCMPSTR, OCMPIFACE:
   1444 		var f string
   1445 		f += exprfmt(n.Left, nprec)
   1446 		f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
   1447 		f += exprfmt(n.Right, nprec+1)
   1448 		return f
   1449 	}
   1450 
   1451 	return fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0))
   1452 }
   1453 
   1454 func nodefmt(n *Node, flag int) string {
   1455 	t := n.Type
   1456 
   1457 	// we almost always want the original, except in export mode for literals
   1458 	// this saves the importer some work, and avoids us having to redo some
   1459 	// special casing for package unsafe
   1460 	if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
   1461 		n = n.Orig
   1462 	}
   1463 
   1464 	if flag&obj.FmtLong != 0 && t != nil {
   1465 		if t.Etype == TNIL {
   1466 			return "nil"
   1467 		} else {
   1468 			return fmt.Sprintf("%v (type %v)", n, t)
   1469 		}
   1470 	}
   1471 
   1472 	// TODO inlining produces expressions with ninits. we can't print these yet.
   1473 
   1474 	if opprec[n.Op] < 0 {
   1475 		return stmtfmt(n)
   1476 	}
   1477 
   1478 	return exprfmt(n, 0)
   1479 }
   1480 
   1481 var dumpdepth int
   1482 
   1483 func indent(buf *bytes.Buffer) {
   1484 	buf.WriteString("\n")
   1485 	for i := 0; i < dumpdepth; i++ {
   1486 		buf.WriteString(".   ")
   1487 	}
   1488 }
   1489 
   1490 func nodedump(n *Node, flag int) string {
   1491 	if n == nil {
   1492 		return ""
   1493 	}
   1494 
   1495 	recur := flag&obj.FmtShort == 0
   1496 
   1497 	var buf bytes.Buffer
   1498 	if recur {
   1499 		indent(&buf)
   1500 		if dumpdepth > 10 {
   1501 			buf.WriteString("...")
   1502 			return buf.String()
   1503 		}
   1504 
   1505 		if n.Ninit != nil {
   1506 			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit)
   1507 			indent(&buf)
   1508 		}
   1509 	}
   1510 
   1511 	switch n.Op {
   1512 	default:
   1513 		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
   1514 
   1515 	case OREGISTER, OINDREG:
   1516 		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Reg)), Jconv(n, 0))
   1517 
   1518 	case OLITERAL:
   1519 		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(n.Val(), 0), Jconv(n, 0))
   1520 
   1521 	case ONAME, ONONAME:
   1522 		if n.Sym != nil {
   1523 			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0))
   1524 		} else {
   1525 			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
   1526 		}
   1527 		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
   1528 			indent(&buf)
   1529 			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
   1530 		}
   1531 
   1532 	case OASOP:
   1533 		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
   1534 
   1535 	case OTYPE:
   1536 		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type)
   1537 		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
   1538 			indent(&buf)
   1539 			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
   1540 		}
   1541 	}
   1542 
   1543 	if n.Sym != nil && n.Op != ONAME {
   1544 		fmt.Fprintf(&buf, " %v", n.Sym)
   1545 	}
   1546 
   1547 	if n.Type != nil {
   1548 		fmt.Fprintf(&buf, " %v", n.Type)
   1549 	}
   1550 
   1551 	if recur {
   1552 		if n.Left != nil {
   1553 			buf.WriteString(Nconv(n.Left, 0))
   1554 		}
   1555 		if n.Right != nil {
   1556 			buf.WriteString(Nconv(n.Right, 0))
   1557 		}
   1558 		if n.List != nil {
   1559 			indent(&buf)
   1560 			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List)
   1561 		}
   1562 
   1563 		if n.Rlist != nil {
   1564 			indent(&buf)
   1565 			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
   1566 		}
   1567 
   1568 		if n.Nbody != nil {
   1569 			indent(&buf)
   1570 			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
   1571 		}
   1572 	}
   1573 
   1574 	return buf.String()
   1575 }
   1576 
   1577 func (s *Sym) String() string {
   1578 	return Sconv(s, 0)
   1579 }
   1580 
   1581 // Fmt "%S": syms
   1582 // Flags:  "%hS" suppresses qualifying with package
   1583 func Sconv(s *Sym, flag int) string {
   1584 	if flag&obj.FmtLong != 0 {
   1585 		panic("linksymfmt")
   1586 	}
   1587 
   1588 	if s == nil {
   1589 		return "<S>"
   1590 	}
   1591 
   1592 	if s.Name == "_" {
   1593 		return "_"
   1594 	}
   1595 
   1596 	sf := flag
   1597 	sm := setfmode(&flag)
   1598 	var r int
   1599 	_ = r
   1600 	str := symfmt(s, flag)
   1601 	flag = sf
   1602 	fmtmode = sm
   1603 	return str
   1604 }
   1605 
   1606 func (t *Type) String() string {
   1607 	return Tconv(t, 0)
   1608 }
   1609 
   1610 // Fmt "%T": types.
   1611 // Flags: 'l' print definition, not name
   1612 //	  'h' omit 'func' and receiver from function types, short type names
   1613 //	  'u' package name, not prefix (FTypeId mode, sticky)
   1614 func Tconv(t *Type, flag int) string {
   1615 	if t == nil {
   1616 		return "<T>"
   1617 	}
   1618 
   1619 	if t.Trecur > 4 {
   1620 		return "<...>"
   1621 	}
   1622 
   1623 	t.Trecur++
   1624 	sf := flag
   1625 	sm := setfmode(&flag)
   1626 
   1627 	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
   1628 		fmtpkgpfx++
   1629 	}
   1630 	if fmtpkgpfx != 0 {
   1631 		flag |= obj.FmtUnsigned
   1632 	}
   1633 
   1634 	var r int
   1635 	_ = r
   1636 	str := typefmt(t, flag)
   1637 
   1638 	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
   1639 		fmtpkgpfx--
   1640 	}
   1641 
   1642 	flag = sf
   1643 	fmtmode = sm
   1644 	t.Trecur--
   1645 	return str
   1646 }
   1647 
   1648 func (n *Node) String() string {
   1649 	return Nconv(n, 0)
   1650 }
   1651 
   1652 // Fmt '%N': Nodes.
   1653 // Flags: 'l' suffix with "(type %T)" where possible
   1654 //	  '+h' in debug mode, don't recurse, no multiline output
   1655 func Nconv(n *Node, flag int) string {
   1656 	if n == nil {
   1657 		return "<N>"
   1658 	}
   1659 	sf := flag
   1660 	sm := setfmode(&flag)
   1661 
   1662 	var r int
   1663 	_ = r
   1664 	var str string
   1665 	switch fmtmode {
   1666 	case FErr, FExp:
   1667 		str = nodefmt(n, flag)
   1668 
   1669 	case FDbg:
   1670 		dumpdepth++
   1671 		str = nodedump(n, flag)
   1672 		dumpdepth--
   1673 
   1674 	default:
   1675 		Fatal("unhandled %%N mode")
   1676 	}
   1677 
   1678 	flag = sf
   1679 	fmtmode = sm
   1680 	return str
   1681 }
   1682 
   1683 func (l *NodeList) String() string {
   1684 	return Hconv(l, 0)
   1685 }
   1686 
   1687 // Fmt '%H': NodeList.
   1688 // Flags: all those of %N plus ',': separate with comma's instead of semicolons.
   1689 func Hconv(l *NodeList, flag int) string {
   1690 	if l == nil && fmtmode == FDbg {
   1691 		return "<nil>"
   1692 	}
   1693 
   1694 	sf := flag
   1695 	sm := setfmode(&flag)
   1696 	var r int
   1697 	_ = r
   1698 	sep := "; "
   1699 	if fmtmode == FDbg {
   1700 		sep = "\n"
   1701 	} else if flag&obj.FmtComma != 0 {
   1702 		sep = ", "
   1703 	}
   1704 
   1705 	var buf bytes.Buffer
   1706 	for ; l != nil; l = l.Next {
   1707 		buf.WriteString(Nconv(l.N, 0))
   1708 		if l.Next != nil {
   1709 			buf.WriteString(sep)
   1710 		}
   1711 	}
   1712 
   1713 	flag = sf
   1714 	fmtmode = sm
   1715 	return buf.String()
   1716 }
   1717 
   1718 func dumplist(s string, l *NodeList) {
   1719 	fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
   1720 }
   1721 
   1722 func Dump(s string, n *Node) {
   1723 	fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
   1724 }
   1725