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