mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Ran rsc.io/grind rev 6f0e601 on the source files. The cleanups move var declarations as close to the use as possible, splitting disjoint uses of the var into separate variables. They also remove dead code (especially in func sudoaddable), which helps with the var moving. There's more cleanup to come, but this alone cuts the time spent compiling html/template on my 2013 MacBook Pro from 3.1 seconds to 2.3 seconds. Change-Id: I4de499f47b1dd47a560c310bbcde6b08d425cfd6 Reviewed-on: https://go-review.googlesource.com/5637 Reviewed-by: Rob Pike <r@golang.org>
2011 lines
42 KiB
Go
2011 lines
42 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gc
|
|
|
|
import (
|
|
"cmd/internal/obj"
|
|
"fmt"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
//
|
|
// Format conversions
|
|
// %L int Line numbers
|
|
//
|
|
// %E int etype values (aka 'Kind')
|
|
//
|
|
// %O int Node Opcodes
|
|
// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
|
|
//
|
|
// %J Node* Node details
|
|
// Flags: "%hJ" suppresses things not relevant until walk.
|
|
//
|
|
// %V Val* Constant values
|
|
//
|
|
// %S Sym* Symbols
|
|
// Flags: +,- #: mode (see below)
|
|
// "%hS" unqualified identifier in any mode
|
|
// "%hhS" in export mode: unqualified identifier if exported, qualified if not
|
|
//
|
|
// %T Type* Types
|
|
// Flags: +,- #: mode (see below)
|
|
// 'l' definition instead of name.
|
|
// 'h' omit "func" and receiver in function types
|
|
// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
|
|
//
|
|
// %N Node* Nodes
|
|
// Flags: +,- #: mode (see below)
|
|
// 'h' (only in +/debug mode) suppress recursion
|
|
// 'l' (only in Error mode) print "foo (type Bar)"
|
|
//
|
|
// %H NodeList* NodeLists
|
|
// Flags: those of %N
|
|
// ',' separate items with ',' instead of ';'
|
|
//
|
|
// %Z Strlit* String literals
|
|
//
|
|
// In mparith1.c:
|
|
// %B Mpint* Big integers
|
|
// %F Mpflt* Big floats
|
|
//
|
|
// %S, %T and %N obey use the following flags to set the format mode:
|
|
const (
|
|
FErr = iota
|
|
FDbg
|
|
FExp
|
|
FTypeId
|
|
)
|
|
|
|
var fmtmode int = FErr
|
|
|
|
var fmtpkgpfx int // %uT stickyness
|
|
|
|
//
|
|
// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
|
|
//
|
|
// The mode flags +, - and # are sticky, meaning they persist through
|
|
// recursions of %N, %T and %S, but not the h and l flags. The u flag is
|
|
// sticky only on %T recursions and only used in %-/Sym mode.
|
|
|
|
//
|
|
// Useful format combinations:
|
|
//
|
|
// %+N %+H multiline recursive debug dump of node/nodelist
|
|
// %+hN %+hH non recursive debug dump
|
|
//
|
|
// %#N %#T export format
|
|
// %#lT type definition instead of name
|
|
// %#hT omit"func" and receiver in function signature
|
|
//
|
|
// %lN "foo (type Bar)" for error messages
|
|
//
|
|
// %-T type identifiers
|
|
// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
|
|
// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
|
|
//
|
|
|
|
func setfmode(flags *int) int {
|
|
fm := fmtmode
|
|
if *flags&obj.FmtSign != 0 {
|
|
fmtmode = FDbg
|
|
} else if *flags&obj.FmtSharp != 0 {
|
|
fmtmode = FExp
|
|
} else if *flags&obj.FmtLeft != 0 {
|
|
fmtmode = FTypeId
|
|
}
|
|
|
|
*flags &^= (obj.FmtSharp | obj.FmtLeft | obj.FmtSign)
|
|
return fm
|
|
}
|
|
|
|
// Fmt "%L": Linenumbers
|
|
|
|
var goopnames = []string{
|
|
OADDR: "&",
|
|
OADD: "+",
|
|
OADDSTR: "+",
|
|
OANDAND: "&&",
|
|
OANDNOT: "&^",
|
|
OAND: "&",
|
|
OAPPEND: "append",
|
|
OAS: "=",
|
|
OAS2: "=",
|
|
OBREAK: "break",
|
|
OCALL: "function call", // not actual syntax
|
|
OCAP: "cap",
|
|
OCASE: "case",
|
|
OCLOSE: "close",
|
|
OCOMPLEX: "complex",
|
|
OCOM: "^",
|
|
OCONTINUE: "continue",
|
|
OCOPY: "copy",
|
|
ODEC: "--",
|
|
ODELETE: "delete",
|
|
ODEFER: "defer",
|
|
ODIV: "/",
|
|
OEQ: "==",
|
|
OFALL: "fallthrough",
|
|
OFOR: "for",
|
|
OGE: ">=",
|
|
OGOTO: "goto",
|
|
OGT: ">",
|
|
OIF: "if",
|
|
OIMAG: "imag",
|
|
OINC: "++",
|
|
OIND: "*",
|
|
OLEN: "len",
|
|
OLE: "<=",
|
|
OLSH: "<<",
|
|
OLT: "<",
|
|
OMAKE: "make",
|
|
OMINUS: "-",
|
|
OMOD: "%",
|
|
OMUL: "*",
|
|
ONEW: "new",
|
|
ONE: "!=",
|
|
ONOT: "!",
|
|
OOROR: "||",
|
|
OOR: "|",
|
|
OPANIC: "panic",
|
|
OPLUS: "+",
|
|
OPRINTN: "println",
|
|
OPRINT: "print",
|
|
ORANGE: "range",
|
|
OREAL: "real",
|
|
ORECV: "<-",
|
|
ORECOVER: "recover",
|
|
ORETURN: "return",
|
|
ORSH: ">>",
|
|
OSELECT: "select",
|
|
OSEND: "<-",
|
|
OSUB: "-",
|
|
OSWITCH: "switch",
|
|
OXOR: "^",
|
|
}
|
|
|
|
// Fmt "%O": Node opcodes
|
|
func Oconv(o int, flag int) string {
|
|
if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode != FDbg {
|
|
if o >= 0 && o < len(goopnames) && goopnames[o] != "" {
|
|
var fp string
|
|
fp += goopnames[o]
|
|
return fp
|
|
}
|
|
}
|
|
|
|
if o >= 0 && o < len(opnames) && opnames[o] != "" {
|
|
var fp string
|
|
fp += opnames[o]
|
|
return fp
|
|
}
|
|
|
|
var fp string
|
|
fp += fmt.Sprintf("O-%d", o)
|
|
return fp
|
|
}
|
|
|
|
var classnames = []string{
|
|
"Pxxx",
|
|
"PEXTERN",
|
|
"PAUTO",
|
|
"PPARAM",
|
|
"PPARAMOUT",
|
|
"PPARAMREF",
|
|
"PFUNC",
|
|
}
|
|
|
|
// Fmt "%J": Node details.
|
|
func Jconv(n *Node, flag int) string {
|
|
var fp string
|
|
|
|
c := flag & obj.FmtShort
|
|
|
|
if c == 0 && n.Ullman != 0 {
|
|
fp += fmt.Sprintf(" u(%d)", n.Ullman)
|
|
}
|
|
|
|
if c == 0 && n.Addable != 0 {
|
|
fp += fmt.Sprintf(" a(%d)", n.Addable)
|
|
}
|
|
|
|
if c == 0 && n.Vargen != 0 {
|
|
fp += fmt.Sprintf(" g(%d)", n.Vargen)
|
|
}
|
|
|
|
if n.Lineno != 0 {
|
|
fp += fmt.Sprintf(" l(%d)", n.Lineno)
|
|
}
|
|
|
|
if c == 0 && n.Xoffset != BADWIDTH {
|
|
fp += fmt.Sprintf(" x(%d%+d)", n.Xoffset, n.Stkdelta)
|
|
}
|
|
|
|
if n.Class != 0 {
|
|
s := ""
|
|
if n.Class&PHEAP != 0 {
|
|
s = ",heap"
|
|
}
|
|
if int(n.Class&^PHEAP) < len(classnames) {
|
|
fp += fmt.Sprintf(" class(%s%s)", classnames[n.Class&^PHEAP], s)
|
|
} else {
|
|
fp += fmt.Sprintf(" class(%d?%s)", n.Class&^PHEAP, s)
|
|
}
|
|
}
|
|
|
|
if n.Colas != 0 {
|
|
fp += fmt.Sprintf(" colas(%d)", n.Colas)
|
|
}
|
|
|
|
if n.Funcdepth != 0 {
|
|
fp += fmt.Sprintf(" f(%d)", n.Funcdepth)
|
|
}
|
|
|
|
switch n.Esc {
|
|
case EscUnknown:
|
|
break
|
|
|
|
case EscHeap:
|
|
fp += fmt.Sprintf(" esc(h)")
|
|
|
|
case EscScope:
|
|
fp += fmt.Sprintf(" esc(s)")
|
|
|
|
case EscNone:
|
|
fp += fmt.Sprintf(" esc(no)")
|
|
|
|
case EscNever:
|
|
if c == 0 {
|
|
fp += fmt.Sprintf(" esc(N)")
|
|
}
|
|
|
|
default:
|
|
fp += fmt.Sprintf(" esc(%d)", n.Esc)
|
|
}
|
|
|
|
if n.Escloopdepth != 0 {
|
|
fp += fmt.Sprintf(" ld(%d)", n.Escloopdepth)
|
|
}
|
|
|
|
if c == 0 && n.Typecheck != 0 {
|
|
fp += fmt.Sprintf(" tc(%d)", n.Typecheck)
|
|
}
|
|
|
|
if c == 0 && n.Dodata != 0 {
|
|
fp += fmt.Sprintf(" dd(%d)", n.Dodata)
|
|
}
|
|
|
|
if n.Isddd != 0 {
|
|
fp += fmt.Sprintf(" isddd(%d)", n.Isddd)
|
|
}
|
|
|
|
if n.Implicit != 0 {
|
|
fp += fmt.Sprintf(" implicit(%d)", n.Implicit)
|
|
}
|
|
|
|
if n.Embedded != 0 {
|
|
fp += fmt.Sprintf(" embedded(%d)", n.Embedded)
|
|
}
|
|
|
|
if n.Addrtaken != 0 {
|
|
fp += fmt.Sprintf(" addrtaken")
|
|
}
|
|
|
|
if n.Assigned != 0 {
|
|
fp += fmt.Sprintf(" assigned")
|
|
}
|
|
|
|
if c == 0 && n.Used != 0 {
|
|
fp += fmt.Sprintf(" used(%d)", n.Used)
|
|
}
|
|
return fp
|
|
}
|
|
|
|
// Fmt "%V": Values
|
|
func Vconv(v *Val, flag int) string {
|
|
switch v.Ctype {
|
|
case CTINT:
|
|
if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Bconv(v.U.Xval, obj.FmtSharp))
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Bconv(v.U.Xval, 0))
|
|
return fp
|
|
|
|
case CTRUNE:
|
|
x := Mpgetfix(v.U.Xval)
|
|
if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
|
|
var fp string
|
|
fp += fmt.Sprintf("'%c'", int(x))
|
|
return fp
|
|
}
|
|
if 0 <= x && x < 1<<16 {
|
|
var fp string
|
|
fp += fmt.Sprintf("'\\u%04x'", uint(int(x)))
|
|
return fp
|
|
}
|
|
if 0 <= x && x <= utf8.MaxRune {
|
|
var fp string
|
|
fp += fmt.Sprintf("'\\U%08x'", uint64(x))
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("('\\x00' + %v)", Bconv(v.U.Xval, 0))
|
|
return fp
|
|
|
|
case CTFLT:
|
|
if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Fconv(v.U.Fval, 0))
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Fconv(v.U.Fval, obj.FmtSharp))
|
|
return fp
|
|
|
|
case CTCPLX:
|
|
if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
|
|
var fp string
|
|
fp += fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, 0), Fconv(&v.U.Cval.Imag, 0))
|
|
return fp
|
|
}
|
|
if mpcmpfltc(&v.U.Cval.Real, 0) == 0 {
|
|
var fp string
|
|
fp += fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
|
return fp
|
|
}
|
|
if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Fconv(&v.U.Cval.Real, obj.FmtSharp))
|
|
return fp
|
|
}
|
|
if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 {
|
|
var fp string
|
|
fp += fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
|
return fp
|
|
|
|
case CTSTR:
|
|
var fp string
|
|
fp += fmt.Sprintf("\"%v\"", Zconv(v.U.Sval, 0))
|
|
return fp
|
|
|
|
case CTBOOL:
|
|
if v.U.Bval != 0 {
|
|
var fp string
|
|
fp += "true"
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += "false"
|
|
return fp
|
|
|
|
case CTNIL:
|
|
var fp string
|
|
fp += "nil"
|
|
return fp
|
|
}
|
|
|
|
var fp string
|
|
fp += fmt.Sprintf("<ctype=%d>", v.Ctype)
|
|
return fp
|
|
}
|
|
|
|
// Fmt "%Z": escaped string literals
|
|
func Zconv(sp *Strlit, flag int) string {
|
|
if sp == nil {
|
|
var fp string
|
|
fp += "<nil>"
|
|
return fp
|
|
}
|
|
|
|
// NOTE: Keep in sync with ../ld/go.c:/^Zconv.
|
|
s := sp.S
|
|
var n int
|
|
var fp string
|
|
for i := 0; i < len(s); i += n {
|
|
var r rune
|
|
r, n = utf8.DecodeRuneInString(s[i:])
|
|
switch r {
|
|
case utf8.RuneError:
|
|
if n == 1 {
|
|
fp += fmt.Sprintf("\\x%02x", s[i])
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
// fall through
|
|
default:
|
|
if r < ' ' {
|
|
fp += fmt.Sprintf("\\x%02x", r)
|
|
break
|
|
}
|
|
|
|
fp += string(r)
|
|
|
|
case '\t':
|
|
fp += "\\t"
|
|
|
|
case '\n':
|
|
fp += "\\n"
|
|
|
|
case '"',
|
|
'\\':
|
|
fp += `\` + string(r)
|
|
|
|
case 0xFEFF: // BOM, basically disallowed in source code
|
|
fp += "\\uFEFF"
|
|
}
|
|
}
|
|
|
|
return fp
|
|
}
|
|
|
|
/*
|
|
s%,%,\n%g
|
|
s%\n+%\n%g
|
|
s%^[ ]*T%%g
|
|
s%,.*%%g
|
|
s%.+% [T&] = "&",%g
|
|
s%^ ........*\]%&~%g
|
|
s%~ %%g
|
|
*/
|
|
var etnames = []string{
|
|
TINT: "INT",
|
|
TUINT: "UINT",
|
|
TINT8: "INT8",
|
|
TUINT8: "UINT8",
|
|
TINT16: "INT16",
|
|
TUINT16: "UINT16",
|
|
TINT32: "INT32",
|
|
TUINT32: "UINT32",
|
|
TINT64: "INT64",
|
|
TUINT64: "UINT64",
|
|
TUINTPTR: "UINTPTR",
|
|
TFLOAT32: "FLOAT32",
|
|
TFLOAT64: "FLOAT64",
|
|
TCOMPLEX64: "COMPLEX64",
|
|
TCOMPLEX128: "COMPLEX128",
|
|
TBOOL: "BOOL",
|
|
TPTR32: "PTR32",
|
|
TPTR64: "PTR64",
|
|
TFUNC: "FUNC",
|
|
TARRAY: "ARRAY",
|
|
TSTRUCT: "STRUCT",
|
|
TCHAN: "CHAN",
|
|
TMAP: "MAP",
|
|
TINTER: "INTER",
|
|
TFORW: "FORW",
|
|
TFIELD: "FIELD",
|
|
TSTRING: "STRING",
|
|
TANY: "ANY",
|
|
}
|
|
|
|
// Fmt "%E": etype
|
|
func Econv(et int, flag int) string {
|
|
if et >= 0 && et < len(etnames) && etnames[et] != "" {
|
|
var fp string
|
|
fp += etnames[et]
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("E-%d", et)
|
|
return fp
|
|
}
|
|
|
|
// Fmt "%S": syms
|
|
func symfmt(s *Sym, flag int) string {
|
|
if s.Pkg != nil && flag&obj.FmtShort == 0 /*untyped*/ {
|
|
switch fmtmode {
|
|
case FErr: // This is for the user
|
|
if s.Pkg == localpkg {
|
|
var fp string
|
|
fp += s.Name
|
|
return fp
|
|
}
|
|
|
|
// If the name was used by multiple packages, display the full path,
|
|
if s.Pkg.Name != "" && Pkglookup(s.Pkg.Name, nil).Npkg > 1 {
|
|
var fp string
|
|
fp += fmt.Sprintf("\"%v\".%s", Zconv(s.Pkg.Path, 0), s.Name)
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
|
|
return fp
|
|
|
|
case FDbg:
|
|
var fp string
|
|
fp += fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
|
|
return fp
|
|
|
|
case FTypeId:
|
|
if flag&obj.FmtUnsigned != 0 /*untyped*/ {
|
|
var fp string
|
|
fp += fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
|
|
return fp // dcommontype, typehash
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name)
|
|
return fp // (methodsym), typesym, weaksym
|
|
|
|
case FExp:
|
|
if s.Name != "" && s.Name[0] == '.' {
|
|
Fatal("exporting synthetic symbol %s", s.Name)
|
|
}
|
|
if s.Pkg != builtinpkg {
|
|
var fp string
|
|
fp += fmt.Sprintf("@\"%v\".%s", Zconv(s.Pkg.Path, 0), s.Name)
|
|
return fp
|
|
}
|
|
}
|
|
}
|
|
|
|
if flag&obj.FmtByte != 0 /*untyped*/ { // FmtByte (hh) implies FmtShort (h)
|
|
|
|
// skip leading "type." in method name
|
|
p := s.Name
|
|
if i := strings.LastIndex(s.Name, "."); i >= 0 {
|
|
p = s.Name[i+1:]
|
|
}
|
|
|
|
// exportname needs to see the name without the prefix too.
|
|
if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
|
|
var fp string
|
|
fp += fmt.Sprintf("@\"%v\".%s", Zconv(s.Pkg.Path, 0), p)
|
|
return fp
|
|
}
|
|
|
|
var fp string
|
|
fp += p
|
|
return fp
|
|
}
|
|
|
|
var fp string
|
|
fp += s.Name
|
|
return fp
|
|
}
|
|
|
|
var basicnames = []string{
|
|
TINT: "int",
|
|
TUINT: "uint",
|
|
TINT8: "int8",
|
|
TUINT8: "uint8",
|
|
TINT16: "int16",
|
|
TUINT16: "uint16",
|
|
TINT32: "int32",
|
|
TUINT32: "uint32",
|
|
TINT64: "int64",
|
|
TUINT64: "uint64",
|
|
TUINTPTR: "uintptr",
|
|
TFLOAT32: "float32",
|
|
TFLOAT64: "float64",
|
|
TCOMPLEX64: "complex64",
|
|
TCOMPLEX128: "complex128",
|
|
TBOOL: "bool",
|
|
TANY: "any",
|
|
TSTRING: "string",
|
|
TNIL: "nil",
|
|
TIDEAL: "untyped number",
|
|
TBLANK: "blank",
|
|
}
|
|
|
|
func typefmt(t *Type, flag int) string {
|
|
if t == nil {
|
|
var fp string
|
|
fp += "<T>"
|
|
return fp
|
|
}
|
|
|
|
if t == bytetype || t == runetype {
|
|
// in %-T mode collapse rune and byte with their originals.
|
|
if fmtmode != FTypeId {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtShort))
|
|
return fp
|
|
}
|
|
t = Types[t.Etype]
|
|
}
|
|
|
|
if t == errortype {
|
|
var fp string
|
|
fp += "error"
|
|
return fp
|
|
}
|
|
|
|
// Unless the 'l' flag was specified, if the type has a name, just print that name.
|
|
if flag&obj.FmtLong == 0 /*untyped*/ && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] {
|
|
switch fmtmode {
|
|
case FTypeId:
|
|
if flag&obj.FmtShort != 0 /*untyped*/ {
|
|
if t.Vargen != 0 {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v·%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
|
|
return fp
|
|
}
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtShort))
|
|
return fp
|
|
}
|
|
|
|
if flag&obj.FmtUnsigned != 0 /*untyped*/ {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtUnsigned))
|
|
return fp
|
|
}
|
|
fallthrough
|
|
|
|
// fallthrough
|
|
case FExp:
|
|
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
|
|
var fp string
|
|
fp += fmt.Sprintf("%v·%d", Sconv(t.Sym, 0), t.Vargen)
|
|
return fp
|
|
}
|
|
}
|
|
|
|
var fp string
|
|
fp += fmt.Sprintf("%v", Sconv(t.Sym, 0))
|
|
return fp
|
|
}
|
|
|
|
var fp string
|
|
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
|
|
if fmtmode == FErr && (t == idealbool || t == idealstring) {
|
|
fp += "untyped "
|
|
}
|
|
fp += basicnames[t.Etype]
|
|
return fp
|
|
}
|
|
|
|
if fmtmode == FDbg {
|
|
fp += fmt.Sprintf("%v-", Econv(int(t.Etype), 0))
|
|
}
|
|
|
|
switch t.Etype {
|
|
case TPTR32,
|
|
TPTR64:
|
|
if fmtmode == FTypeId && (flag&obj.FmtShort != 0 /*untyped*/) {
|
|
fp += fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
|
|
return fp
|
|
}
|
|
fp += fmt.Sprintf("*%v", Tconv(t.Type, 0))
|
|
return fp
|
|
|
|
case TARRAY:
|
|
if t.Bound >= 0 {
|
|
fp += fmt.Sprintf("[%d]%v", t.Bound, Tconv(t.Type, 0))
|
|
return fp
|
|
}
|
|
if t.Bound == -100 {
|
|
fp += fmt.Sprintf("[...]%v", Tconv(t.Type, 0))
|
|
return fp
|
|
}
|
|
fp += fmt.Sprintf("[]%v", Tconv(t.Type, 0))
|
|
return fp
|
|
|
|
case TCHAN:
|
|
switch t.Chan {
|
|
case Crecv:
|
|
fp += fmt.Sprintf("<-chan %v", Tconv(t.Type, 0))
|
|
return fp
|
|
|
|
case Csend:
|
|
fp += fmt.Sprintf("chan<- %v", Tconv(t.Type, 0))
|
|
return fp
|
|
}
|
|
|
|
if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
|
|
fp += fmt.Sprintf("chan (%v)", Tconv(t.Type, 0))
|
|
return fp
|
|
}
|
|
fp += fmt.Sprintf("chan %v", Tconv(t.Type, 0))
|
|
return fp
|
|
|
|
case TMAP:
|
|
fp += fmt.Sprintf("map[%v]%v", Tconv(t.Down, 0), Tconv(t.Type, 0))
|
|
return fp
|
|
|
|
case TINTER:
|
|
fp += "interface {"
|
|
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
|
if exportname(t1.Sym.Name) {
|
|
if t1.Down != nil {
|
|
fp += fmt.Sprintf(" %v%v;", Sconv(t1.Sym, obj.FmtShort), Tconv(t1.Type, obj.FmtShort))
|
|
} else {
|
|
fp += fmt.Sprintf(" %v%v ", Sconv(t1.Sym, obj.FmtShort), Tconv(t1.Type, obj.FmtShort))
|
|
}
|
|
} else {
|
|
// non-exported method names must be qualified
|
|
if t1.Down != nil {
|
|
fp += fmt.Sprintf(" %v%v;", Sconv(t1.Sym, obj.FmtUnsigned), Tconv(t1.Type, obj.FmtShort))
|
|
} else {
|
|
fp += fmt.Sprintf(" %v%v ", Sconv(t1.Sym, obj.FmtUnsigned), Tconv(t1.Type, obj.FmtShort))
|
|
}
|
|
}
|
|
}
|
|
|
|
fp += "}"
|
|
return fp
|
|
|
|
case TFUNC:
|
|
if flag&obj.FmtShort != 0 /*untyped*/ {
|
|
fp += fmt.Sprintf("%v", Tconv(getinargx(t), 0))
|
|
} else {
|
|
if t.Thistuple != 0 {
|
|
fp += fmt.Sprintf("method%v func%v", Tconv(getthisx(t), 0), Tconv(getinargx(t), 0))
|
|
} else {
|
|
fp += fmt.Sprintf("func%v", Tconv(getinargx(t), 0))
|
|
}
|
|
}
|
|
|
|
switch t.Outtuple {
|
|
case 0:
|
|
break
|
|
|
|
case 1:
|
|
if fmtmode != FExp {
|
|
fp += fmt.Sprintf(" %v", Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
default:
|
|
fp += fmt.Sprintf(" %v", Tconv(getoutargx(t), 0))
|
|
}
|
|
|
|
return fp
|
|
|
|
// Format the bucket struct for map[x]y as map.bucket[x]y.
|
|
// This avoids a recursive print that generates very long names.
|
|
case TSTRUCT:
|
|
if t.Map != nil {
|
|
if t.Map.Bucket == t {
|
|
fp += fmt.Sprintf("map.bucket[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
|
|
return fp
|
|
}
|
|
|
|
if t.Map.Hmap == t {
|
|
fp += fmt.Sprintf("map.hdr[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
|
|
return fp
|
|
}
|
|
|
|
if t.Map.Hiter == t {
|
|
fp += fmt.Sprintf("map.iter[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
|
|
return fp
|
|
}
|
|
|
|
Yyerror("unknown internal map type")
|
|
}
|
|
|
|
if t.Funarg != 0 {
|
|
fp += "("
|
|
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
|
|
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
|
if t1.Down != nil {
|
|
fp += fmt.Sprintf("%v, ", Tconv(t1, obj.FmtShort))
|
|
} else {
|
|
fp += fmt.Sprintf("%v", Tconv(t1, obj.FmtShort))
|
|
}
|
|
}
|
|
} else {
|
|
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
|
if t1.Down != nil {
|
|
fp += fmt.Sprintf("%v, ", Tconv(t1, 0))
|
|
} else {
|
|
fp += fmt.Sprintf("%v", Tconv(t1, 0))
|
|
}
|
|
}
|
|
}
|
|
|
|
fp += ")"
|
|
} else {
|
|
fp += "struct {"
|
|
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
|
if t1.Down != nil {
|
|
fp += fmt.Sprintf(" %v;", Tconv(t1, obj.FmtLong))
|
|
} else {
|
|
fp += fmt.Sprintf(" %v ", Tconv(t1, obj.FmtLong))
|
|
}
|
|
}
|
|
fp += "}"
|
|
}
|
|
|
|
return fp
|
|
|
|
case TFIELD:
|
|
if flag&obj.FmtShort == 0 /*untyped*/ {
|
|
s := t.Sym
|
|
|
|
// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
|
|
// ~r%d is a (formerly) unnamed result.
|
|
if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil {
|
|
if t.Nname.Orig != nil {
|
|
s = t.Nname.Orig.Sym
|
|
if s != nil && s.Name[0] == '~' {
|
|
if s.Name[1] == 'r' { // originally an unnamed result
|
|
s = nil
|
|
} else if s.Name[1] == 'b' { // originally the blank identifier _
|
|
s = Lookup("_")
|
|
}
|
|
}
|
|
} else {
|
|
s = nil
|
|
}
|
|
}
|
|
|
|
if s != nil && t.Embedded == 0 {
|
|
if t.Funarg != 0 {
|
|
fp += fmt.Sprintf("%v ", Nconv(t.Nname, 0))
|
|
} else if flag&obj.FmtLong != 0 /*untyped*/ {
|
|
fp += fmt.Sprintf("%v ", Sconv(s, obj.FmtShort|obj.FmtByte)) // qualify non-exported names (used on structs, not on funarg)
|
|
} else {
|
|
fp += fmt.Sprintf("%v ", Sconv(s, 0))
|
|
}
|
|
} else if fmtmode == FExp {
|
|
// TODO(rsc) this breaks on the eliding of unused arguments in the backend
|
|
// when this is fixed, the special case in dcl.c checkarglist can go.
|
|
//if(t->funarg)
|
|
// fmtstrcpy(fp, "_ ");
|
|
//else
|
|
if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path.S) > 0 {
|
|
fp += fmt.Sprintf("@\"%v\".? ", Zconv(s.Pkg.Path, 0))
|
|
} else {
|
|
fp += "? "
|
|
}
|
|
}
|
|
}
|
|
|
|
if t.Isddd != 0 {
|
|
fp += fmt.Sprintf("...%v", Tconv(t.Type.Type, 0))
|
|
} else {
|
|
fp += fmt.Sprintf("%v", Tconv(t.Type, 0))
|
|
}
|
|
|
|
if flag&obj.FmtShort == 0 /*untyped*/ && t.Note != nil {
|
|
fp += fmt.Sprintf(" \"%v\"", Zconv(t.Note, 0))
|
|
}
|
|
return fp
|
|
|
|
case TFORW:
|
|
if t.Sym != nil {
|
|
fp += fmt.Sprintf("undefined %v", Sconv(t.Sym, 0))
|
|
return fp
|
|
}
|
|
fp += "undefined"
|
|
return fp
|
|
|
|
case TUNSAFEPTR:
|
|
if fmtmode == FExp {
|
|
fp += fmt.Sprintf("@\"unsafe\".Pointer")
|
|
return fp
|
|
}
|
|
fp += fmt.Sprintf("unsafe.Pointer")
|
|
return fp
|
|
}
|
|
|
|
if fmtmode == FExp {
|
|
Fatal("missing %v case during export", Econv(int(t.Etype), 0))
|
|
}
|
|
|
|
// Don't know how to handle - fall back to detailed prints.
|
|
fp += fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), Sconv(t.Sym, 0), Tconv(t.Type, 0))
|
|
return fp
|
|
}
|
|
|
|
// Statements which may be rendered with a simplestmt as init.
|
|
func stmtwithinit(op int) bool {
|
|
switch op {
|
|
case OIF,
|
|
OFOR,
|
|
OSWITCH:
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func stmtfmt(n *Node) string {
|
|
var f string
|
|
|
|
// some statements allow for an init, but at most one,
|
|
// but we may have an arbitrary number added, eg by typecheck
|
|
// and inlining. If it doesn't fit the syntax, emit an enclosing
|
|
// block starting with the init statements.
|
|
|
|
// if we can just say "for" n->ninit; ... then do so
|
|
simpleinit := n.Ninit != nil && n.Ninit.Next == nil && n.Ninit.N.Ninit == nil && stmtwithinit(int(n.Op))
|
|
|
|
// otherwise, print the inits as separate statements
|
|
complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr)
|
|
|
|
// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
|
|
extrablock := complexinit && stmtwithinit(int(n.Op))
|
|
|
|
if extrablock {
|
|
f += "{"
|
|
}
|
|
|
|
if complexinit {
|
|
f += fmt.Sprintf(" %v; ", Hconv(n.Ninit, 0))
|
|
}
|
|
|
|
switch n.Op {
|
|
case ODCL:
|
|
if fmtmode == FExp {
|
|
switch n.Left.Class &^ PHEAP {
|
|
case PPARAM,
|
|
PPARAMOUT,
|
|
PAUTO:
|
|
f += fmt.Sprintf("var %v %v", Nconv(n.Left, 0), Tconv(n.Left.Type, 0))
|
|
goto ret
|
|
}
|
|
}
|
|
|
|
f += fmt.Sprintf("var %v %v", Sconv(n.Left.Sym, 0), Tconv(n.Left.Type, 0))
|
|
|
|
case ODCLFIELD:
|
|
if n.Left != nil {
|
|
f += fmt.Sprintf("%v %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
} else {
|
|
f += fmt.Sprintf("%v", Nconv(n.Right, 0))
|
|
}
|
|
|
|
// Don't export "v = <N>" initializing statements, hope they're always
|
|
// preceded by the DCL which will be re-parsed and typecheck to reproduce
|
|
// the "v = <N>" again.
|
|
case OAS:
|
|
if fmtmode == FExp && n.Right == nil {
|
|
break
|
|
}
|
|
|
|
if n.Colas != 0 && !complexinit {
|
|
f += fmt.Sprintf("%v := %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
} else {
|
|
f += fmt.Sprintf("%v = %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
}
|
|
|
|
case OASOP:
|
|
if n.Implicit != 0 {
|
|
if n.Etype == OADD {
|
|
f += fmt.Sprintf("%v++", Nconv(n.Left, 0))
|
|
} else {
|
|
f += fmt.Sprintf("%v--", Nconv(n.Left, 0))
|
|
}
|
|
break
|
|
}
|
|
|
|
f += fmt.Sprintf("%v %v= %v", Nconv(n.Left, 0), Oconv(int(n.Etype), obj.FmtSharp), Nconv(n.Right, 0))
|
|
|
|
case OAS2:
|
|
if n.Colas != 0 && !complexinit {
|
|
f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
// fallthrough
|
|
case OAS2DOTTYPE,
|
|
OAS2FUNC,
|
|
OAS2MAPR,
|
|
OAS2RECV:
|
|
f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
|
|
|
|
case ORETURN:
|
|
f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
|
|
|
|
case ORETJMP:
|
|
f += fmt.Sprintf("retjmp %v", Sconv(n.Sym, 0))
|
|
|
|
case OPROC:
|
|
f += fmt.Sprintf("go %v", Nconv(n.Left, 0))
|
|
|
|
case ODEFER:
|
|
f += fmt.Sprintf("defer %v", Nconv(n.Left, 0))
|
|
|
|
case OIF:
|
|
if simpleinit {
|
|
f += fmt.Sprintf("if %v; %v { %v }", Nconv(n.Ninit.N, 0), Nconv(n.Ntest, 0), Hconv(n.Nbody, 0))
|
|
} else {
|
|
f += fmt.Sprintf("if %v { %v }", Nconv(n.Ntest, 0), Hconv(n.Nbody, 0))
|
|
}
|
|
if n.Nelse != nil {
|
|
f += fmt.Sprintf(" else { %v }", Hconv(n.Nelse, 0))
|
|
}
|
|
|
|
case OFOR:
|
|
if fmtmode == FErr { // TODO maybe only if FmtShort, same below
|
|
f += "for loop"
|
|
break
|
|
}
|
|
|
|
f += "for"
|
|
if simpleinit {
|
|
f += fmt.Sprintf(" %v;", Nconv(n.Ninit.N, 0))
|
|
} else if n.Nincr != nil {
|
|
f += " ;"
|
|
}
|
|
|
|
if n.Ntest != nil {
|
|
f += fmt.Sprintf(" %v", Nconv(n.Ntest, 0))
|
|
}
|
|
|
|
if n.Nincr != nil {
|
|
f += fmt.Sprintf("; %v", Nconv(n.Nincr, 0))
|
|
} else if simpleinit {
|
|
f += ";"
|
|
}
|
|
|
|
f += fmt.Sprintf(" { %v }", Hconv(n.Nbody, 0))
|
|
|
|
case ORANGE:
|
|
if fmtmode == FErr {
|
|
f += "for loop"
|
|
break
|
|
}
|
|
|
|
if n.List == nil {
|
|
f += fmt.Sprintf("for range %v { %v }", Nconv(n.Right, 0), Hconv(n.Nbody, 0))
|
|
break
|
|
}
|
|
|
|
f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), Nconv(n.Right, 0), Hconv(n.Nbody, 0))
|
|
|
|
case OSELECT,
|
|
OSWITCH:
|
|
if fmtmode == FErr {
|
|
f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
|
|
break
|
|
}
|
|
|
|
f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
|
|
if simpleinit {
|
|
f += fmt.Sprintf(" %v;", Nconv(n.Ninit.N, 0))
|
|
}
|
|
if n.Ntest != nil {
|
|
f += fmt.Sprintf("%v", Nconv(n.Ntest, 0))
|
|
}
|
|
|
|
f += fmt.Sprintf(" { %v }", Hconv(n.List, 0))
|
|
|
|
case OCASE,
|
|
OXCASE:
|
|
if n.List != nil {
|
|
f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), Hconv(n.Nbody, 0))
|
|
} else {
|
|
f += fmt.Sprintf("default: %v", Hconv(n.Nbody, 0))
|
|
}
|
|
|
|
case OBREAK,
|
|
OCONTINUE,
|
|
OGOTO,
|
|
OFALL,
|
|
OXFALL:
|
|
if n.Left != nil {
|
|
f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
|
|
} else {
|
|
f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
|
|
}
|
|
|
|
case OEMPTY:
|
|
break
|
|
|
|
case OLABEL:
|
|
f += fmt.Sprintf("%v: ", Nconv(n.Left, 0))
|
|
}
|
|
|
|
ret:
|
|
if extrablock {
|
|
f += "}"
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
var opprec = []int{
|
|
OAPPEND: 8,
|
|
OARRAYBYTESTR: 8,
|
|
OARRAYLIT: 8,
|
|
OARRAYRUNESTR: 8,
|
|
OCALLFUNC: 8,
|
|
OCALLINTER: 8,
|
|
OCALLMETH: 8,
|
|
OCALL: 8,
|
|
OCAP: 8,
|
|
OCLOSE: 8,
|
|
OCONVIFACE: 8,
|
|
OCONVNOP: 8,
|
|
OCONV: 8,
|
|
OCOPY: 8,
|
|
ODELETE: 8,
|
|
OLEN: 8,
|
|
OLITERAL: 8,
|
|
OMAKESLICE: 8,
|
|
OMAKE: 8,
|
|
OMAPLIT: 8,
|
|
ONAME: 8,
|
|
ONEW: 8,
|
|
ONONAME: 8,
|
|
OPACK: 8,
|
|
OPANIC: 8,
|
|
OPAREN: 8,
|
|
OPRINTN: 8,
|
|
OPRINT: 8,
|
|
ORUNESTR: 8,
|
|
OSTRARRAYBYTE: 8,
|
|
OSTRARRAYRUNE: 8,
|
|
OSTRUCTLIT: 8,
|
|
OTARRAY: 8,
|
|
OTCHAN: 8,
|
|
OTFUNC: 8,
|
|
OTINTER: 8,
|
|
OTMAP: 8,
|
|
OTSTRUCT: 8,
|
|
OINDEXMAP: 8,
|
|
OINDEX: 8,
|
|
OSLICE: 8,
|
|
OSLICESTR: 8,
|
|
OSLICEARR: 8,
|
|
OSLICE3: 8,
|
|
OSLICE3ARR: 8,
|
|
ODOTINTER: 8,
|
|
ODOTMETH: 8,
|
|
ODOTPTR: 8,
|
|
ODOTTYPE2: 8,
|
|
ODOTTYPE: 8,
|
|
ODOT: 8,
|
|
OXDOT: 8,
|
|
OCALLPART: 8,
|
|
OPLUS: 7,
|
|
ONOT: 7,
|
|
OCOM: 7,
|
|
OMINUS: 7,
|
|
OADDR: 7,
|
|
OIND: 7,
|
|
ORECV: 7,
|
|
OMUL: 6,
|
|
ODIV: 6,
|
|
OMOD: 6,
|
|
OLSH: 6,
|
|
ORSH: 6,
|
|
OAND: 6,
|
|
OANDNOT: 6,
|
|
OADD: 5,
|
|
OSUB: 5,
|
|
OOR: 5,
|
|
OXOR: 5,
|
|
OEQ: 4,
|
|
OLT: 4,
|
|
OLE: 4,
|
|
OGE: 4,
|
|
OGT: 4,
|
|
ONE: 4,
|
|
OCMPSTR: 4,
|
|
OCMPIFACE: 4,
|
|
OSEND: 3,
|
|
OANDAND: 2,
|
|
OOROR: 1,
|
|
// Statements handled by stmtfmt
|
|
OAS: -1,
|
|
OAS2: -1,
|
|
OAS2DOTTYPE: -1,
|
|
OAS2FUNC: -1,
|
|
OAS2MAPR: -1,
|
|
OAS2RECV: -1,
|
|
OASOP: -1,
|
|
OBREAK: -1,
|
|
OCASE: -1,
|
|
OCONTINUE: -1,
|
|
ODCL: -1,
|
|
ODCLFIELD: -1,
|
|
ODEFER: -1,
|
|
OEMPTY: -1,
|
|
OFALL: -1,
|
|
OFOR: -1,
|
|
OGOTO: -1,
|
|
OIF: -1,
|
|
OLABEL: -1,
|
|
OPROC: -1,
|
|
ORANGE: -1,
|
|
ORETURN: -1,
|
|
OSELECT: -1,
|
|
OSWITCH: -1,
|
|
OXCASE: -1,
|
|
OXFALL: -1,
|
|
OEND: 0,
|
|
}
|
|
|
|
func exprfmt(n *Node, prec int) string {
|
|
for n != nil && n.Implicit != 0 && (n.Op == OIND || n.Op == OADDR) {
|
|
n = n.Left
|
|
}
|
|
|
|
if n == nil {
|
|
var f string
|
|
f += "<N>"
|
|
return f
|
|
}
|
|
|
|
nprec := opprec[n.Op]
|
|
if n.Op == OTYPE && n.Sym != nil {
|
|
nprec = 8
|
|
}
|
|
|
|
if prec > nprec {
|
|
var f string
|
|
f += fmt.Sprintf("(%v)", Nconv(n, 0))
|
|
return f
|
|
}
|
|
|
|
switch n.Op {
|
|
case OPAREN:
|
|
var f string
|
|
f += fmt.Sprintf("(%v)", Nconv(n.Left, 0))
|
|
return f
|
|
|
|
case ODDDARG:
|
|
var f string
|
|
f += fmt.Sprintf("... argument")
|
|
return f
|
|
|
|
case OREGISTER:
|
|
var f string
|
|
f += fmt.Sprintf("%v", Ctxt.Rconv(int(n.Val.U.Reg)))
|
|
return f
|
|
|
|
case OLITERAL: // this is a bit of a mess
|
|
if fmtmode == FErr && n.Sym != nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v", Sconv(n.Sym, 0))
|
|
return f
|
|
}
|
|
if n.Val.Ctype == CTNIL && n.Orig != nil && n.Orig != n {
|
|
var f string
|
|
f += exprfmt(n.Orig, prec)
|
|
return f
|
|
}
|
|
if n.Type != nil && n.Type != Types[n.Type.Etype] && n.Type != idealbool && n.Type != idealstring {
|
|
// Need parens when type begins with what might
|
|
// be misinterpreted as a unary operator: * or <-.
|
|
if Isptr[n.Type.Etype] != 0 || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
|
|
var f string
|
|
f += fmt.Sprintf("(%v)(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
|
|
return f
|
|
}
|
|
}
|
|
|
|
var f string
|
|
f += fmt.Sprintf("%v", Vconv(&n.Val, 0))
|
|
return f
|
|
|
|
// Special case: name used as local variable in export.
|
|
// _ becomes ~b%d internally; print as _ for export
|
|
case ONAME:
|
|
if fmtmode == FExp && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
|
var f string
|
|
f += fmt.Sprintf("_")
|
|
return f
|
|
}
|
|
if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Vargen > 0 {
|
|
var f string
|
|
f += fmt.Sprintf("%v·%d", Sconv(n.Sym, 0), n.Vargen)
|
|
return f
|
|
}
|
|
|
|
// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
|
|
// but for export, this should be rendered as (*pkg.T).meth.
|
|
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
|
|
if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
|
|
if Isptr[n.Left.Type.Etype] != 0 {
|
|
var f string
|
|
f += fmt.Sprintf("(%v).%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("%v.%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
|
|
return f
|
|
}
|
|
}
|
|
fallthrough
|
|
|
|
//fallthrough
|
|
case OPACK,
|
|
ONONAME:
|
|
var f string
|
|
f += fmt.Sprintf("%v", Sconv(n.Sym, 0))
|
|
return f
|
|
|
|
case OTYPE:
|
|
if n.Type == nil && n.Sym != nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v", Sconv(n.Sym, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("%v", Tconv(n.Type, 0))
|
|
return f
|
|
|
|
case OTARRAY:
|
|
if n.Left != nil {
|
|
var f string
|
|
f += fmt.Sprintf("[]%v", Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("[]%v", Nconv(n.Right, 0))
|
|
return f // happens before typecheck
|
|
|
|
case OTMAP:
|
|
var f string
|
|
f += fmt.Sprintf("map[%v]%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
return f
|
|
|
|
case OTCHAN:
|
|
switch n.Etype {
|
|
case Crecv:
|
|
var f string
|
|
f += fmt.Sprintf("<-chan %v", Nconv(n.Left, 0))
|
|
return f
|
|
|
|
case Csend:
|
|
var f string
|
|
f += fmt.Sprintf("chan<- %v", Nconv(n.Left, 0))
|
|
return f
|
|
|
|
default:
|
|
if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
|
|
var f string
|
|
f += fmt.Sprintf("chan (%v)", Nconv(n.Left, 0))
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("chan %v", Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
}
|
|
fallthrough
|
|
|
|
case OTSTRUCT:
|
|
var f string
|
|
f += fmt.Sprintf("<struct>")
|
|
return f
|
|
|
|
case OTINTER:
|
|
var f string
|
|
f += fmt.Sprintf("<inter>")
|
|
return f
|
|
|
|
case OTFUNC:
|
|
var f string
|
|
f += fmt.Sprintf("<func>")
|
|
return f
|
|
|
|
case OCLOSURE:
|
|
if fmtmode == FErr {
|
|
var f string
|
|
f += "func literal"
|
|
return f
|
|
}
|
|
if n.Nbody != nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Nbody, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Closure.Nbody, 0))
|
|
return f
|
|
|
|
case OCOMPLIT:
|
|
ptrlit := n.Right != nil && n.Right.Implicit != 0 && n.Right.Type != nil && Isptr[n.Right.Type.Etype] != 0
|
|
if fmtmode == FErr {
|
|
if n.Right != nil && n.Right.Type != nil && n.Implicit == 0 {
|
|
if ptrlit {
|
|
var f string
|
|
f += fmt.Sprintf("&%v literal", Tconv(n.Right.Type.Type, 0))
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("%v literal", Tconv(n.Right.Type, 0))
|
|
return f
|
|
}
|
|
}
|
|
|
|
var f string
|
|
f += "composite literal"
|
|
return f
|
|
}
|
|
|
|
if fmtmode == FExp && ptrlit {
|
|
// typecheck has overwritten OIND by OTYPE with pointer type.
|
|
var f string
|
|
f += fmt.Sprintf("(&%v{ %v })", Tconv(n.Right.Type.Type, 0), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
}
|
|
|
|
var f string
|
|
f += fmt.Sprintf("(%v{ %v })", Nconv(n.Right, 0), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
|
|
case OPTRLIT:
|
|
if fmtmode == FExp && n.Left.Implicit != 0 {
|
|
var f string
|
|
f += fmt.Sprintf("%v", Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("&%v", Nconv(n.Left, 0))
|
|
return f
|
|
|
|
case OSTRUCTLIT:
|
|
if fmtmode == FExp { // requires special handling of field names
|
|
var f string
|
|
if n.Implicit != 0 {
|
|
f += "{"
|
|
} else {
|
|
f += fmt.Sprintf("(%v{", Tconv(n.Type, 0))
|
|
}
|
|
for l := n.List; l != nil; l = l.Next {
|
|
f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), Nconv(l.N.Right, 0))
|
|
|
|
if l.Next != nil {
|
|
f += ","
|
|
} else {
|
|
f += " "
|
|
}
|
|
}
|
|
|
|
if n.Implicit == 0 {
|
|
f += "})"
|
|
return f
|
|
}
|
|
f += "}"
|
|
return f
|
|
}
|
|
fallthrough
|
|
|
|
// fallthrough
|
|
|
|
case OARRAYLIT,
|
|
OMAPLIT:
|
|
if fmtmode == FErr {
|
|
var f string
|
|
f += fmt.Sprintf("%v literal", Tconv(n.Type, 0))
|
|
return f
|
|
}
|
|
if fmtmode == FExp && n.Implicit != 0 {
|
|
var f string
|
|
f += fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("(%v{ %v })", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
|
|
case OKEY:
|
|
if n.Left != nil && n.Right != nil {
|
|
if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
|
|
// requires special handling of field names
|
|
var f string
|
|
f += fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), Nconv(n.Right, 0))
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("%v:%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
return f
|
|
}
|
|
}
|
|
|
|
if n.Left == nil && n.Right != nil {
|
|
var f string
|
|
f += fmt.Sprintf(":%v", Nconv(n.Right, 0))
|
|
return f
|
|
}
|
|
if n.Left != nil && n.Right == nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v:", Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += ":"
|
|
return f
|
|
|
|
case OXDOT,
|
|
ODOT,
|
|
ODOTPTR,
|
|
ODOTINTER,
|
|
ODOTMETH,
|
|
OCALLPART:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
if n.Right == nil || n.Right.Sym == nil {
|
|
f += ".<nil>"
|
|
return f
|
|
}
|
|
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
|
|
return f
|
|
|
|
case ODOTTYPE,
|
|
ODOTTYPE2:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
if n.Right != nil {
|
|
f += fmt.Sprintf(".(%v)", Nconv(n.Right, 0))
|
|
return f
|
|
}
|
|
f += fmt.Sprintf(".(%v)", Tconv(n.Type, 0))
|
|
return f
|
|
|
|
case OINDEX,
|
|
OINDEXMAP,
|
|
OSLICE,
|
|
OSLICESTR,
|
|
OSLICEARR,
|
|
OSLICE3,
|
|
OSLICE3ARR:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
f += fmt.Sprintf("[%v]", Nconv(n.Right, 0))
|
|
return f
|
|
|
|
case OCOPY,
|
|
OCOMPLEX:
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
return f
|
|
|
|
case OCONV,
|
|
OCONVIFACE,
|
|
OCONVNOP,
|
|
OARRAYBYTESTR,
|
|
OARRAYRUNESTR,
|
|
OSTRARRAYBYTE,
|
|
OSTRARRAYRUNE,
|
|
ORUNESTR:
|
|
if n.Type == nil || n.Type.Sym == nil {
|
|
var f string
|
|
f += fmt.Sprintf("(%v)(%v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
if n.Left != nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
|
|
case OREAL,
|
|
OIMAG,
|
|
OAPPEND,
|
|
OCAP,
|
|
OCLOSE,
|
|
ODELETE,
|
|
OLEN,
|
|
OMAKE,
|
|
ONEW,
|
|
OPANIC,
|
|
ORECOVER,
|
|
OPRINT,
|
|
OPRINTN:
|
|
if n.Left != nil {
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
if n.Isddd != 0 {
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
|
|
case OCALL,
|
|
OCALLFUNC,
|
|
OCALLINTER,
|
|
OCALLMETH:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
if n.Isddd != 0 {
|
|
f += fmt.Sprintf("(%v...)", Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
}
|
|
f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
|
|
case OMAKEMAP,
|
|
OMAKECHAN,
|
|
OMAKESLICE:
|
|
if n.List != nil { // pre-typecheck
|
|
var f string
|
|
f += fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
|
|
return f
|
|
}
|
|
if n.Right != nil {
|
|
var f string
|
|
f += fmt.Sprintf("make(%v, %v, %v)", Tconv(n.Type, 0), Nconv(n.Left, 0), Nconv(n.Right, 0))
|
|
return f
|
|
}
|
|
if n.Left != nil {
|
|
var f string
|
|
f += fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
|
|
return f
|
|
}
|
|
var f string
|
|
f += fmt.Sprintf("make(%v)", Tconv(n.Type, 0))
|
|
return f
|
|
|
|
// Unary
|
|
case OPLUS,
|
|
OMINUS,
|
|
OADDR,
|
|
OCOM,
|
|
OIND,
|
|
ONOT,
|
|
ORECV:
|
|
var f string
|
|
if n.Left.Op == n.Op {
|
|
f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp))
|
|
} else {
|
|
f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
|
|
}
|
|
f += exprfmt(n.Left, nprec+1)
|
|
return f
|
|
|
|
// Binary
|
|
case OADD,
|
|
OAND,
|
|
OANDAND,
|
|
OANDNOT,
|
|
ODIV,
|
|
OEQ,
|
|
OGE,
|
|
OGT,
|
|
OLE,
|
|
OLT,
|
|
OLSH,
|
|
OMOD,
|
|
OMUL,
|
|
ONE,
|
|
OOR,
|
|
OOROR,
|
|
ORSH,
|
|
OSEND,
|
|
OSUB,
|
|
OXOR:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
|
|
f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp))
|
|
f += exprfmt(n.Right, nprec+1)
|
|
return f
|
|
|
|
case OADDSTR:
|
|
var f string
|
|
for l := n.List; l != nil; l = l.Next {
|
|
if l != n.List {
|
|
f += fmt.Sprintf(" + ")
|
|
}
|
|
f += exprfmt(l.N, nprec)
|
|
}
|
|
|
|
return f
|
|
|
|
case OCMPSTR,
|
|
OCMPIFACE:
|
|
var f string
|
|
f += exprfmt(n.Left, nprec)
|
|
f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
|
|
f += exprfmt(n.Right, nprec+1)
|
|
return f
|
|
}
|
|
|
|
var f string
|
|
f += fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0))
|
|
return f
|
|
}
|
|
|
|
func nodefmt(n *Node, flag int) string {
|
|
t := n.Type
|
|
|
|
// we almost always want the original, except in export mode for literals
|
|
// this saves the importer some work, and avoids us having to redo some
|
|
// special casing for package unsafe
|
|
if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
|
|
n = n.Orig
|
|
}
|
|
|
|
if flag&obj.FmtLong != 0 /*untyped*/ && t != nil {
|
|
if t.Etype == TNIL {
|
|
var f string
|
|
f += fmt.Sprintf("nil")
|
|
return f
|
|
} else {
|
|
var f string
|
|
f += fmt.Sprintf("%v (type %v)", Nconv(n, 0), Tconv(t, 0))
|
|
return f
|
|
}
|
|
}
|
|
|
|
// TODO inlining produces expressions with ninits. we can't print these yet.
|
|
|
|
if opprec[n.Op] < 0 {
|
|
return stmtfmt(n)
|
|
}
|
|
|
|
var f string
|
|
f += exprfmt(n, 0)
|
|
return f
|
|
}
|
|
|
|
var dumpdepth int
|
|
|
|
func indent(s string) string {
|
|
return s + "\n" + strings.Repeat(". ", dumpdepth)
|
|
}
|
|
|
|
func nodedump(n *Node, flag int) string {
|
|
if n == nil {
|
|
var fp string
|
|
return fp
|
|
}
|
|
|
|
recur := flag&obj.FmtShort == 0 /*untyped*/
|
|
|
|
var fp string
|
|
if recur {
|
|
fp = indent(fp)
|
|
if dumpdepth > 10 {
|
|
fp += "..."
|
|
return fp
|
|
}
|
|
|
|
if n.Ninit != nil {
|
|
fp += fmt.Sprintf("%v-init%v", Oconv(int(n.Op), 0), Hconv(n.Ninit, 0))
|
|
fp = indent(fp)
|
|
}
|
|
}
|
|
|
|
// fmtprint(fp, "[%p]", n);
|
|
|
|
switch n.Op {
|
|
default:
|
|
fp += fmt.Sprintf("%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
|
|
|
|
case OREGISTER,
|
|
OINDREG:
|
|
fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Ctxt.Rconv(int(n.Val.U.Reg)), Jconv(n, 0))
|
|
|
|
case OLITERAL:
|
|
fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Vconv(&n.Val, 0), Jconv(n, 0))
|
|
|
|
case ONAME,
|
|
ONONAME:
|
|
if n.Sym != nil {
|
|
fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0))
|
|
} else {
|
|
fp += fmt.Sprintf("%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
|
|
}
|
|
if recur && n.Type == nil && n.Ntype != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
|
|
}
|
|
|
|
case OASOP:
|
|
fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
|
|
|
|
case OTYPE:
|
|
fp += fmt.Sprintf("%v %v%v type=%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0), Tconv(n.Type, 0))
|
|
if recur && n.Type == nil && n.Ntype != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
|
|
}
|
|
}
|
|
|
|
if n.Sym != nil && n.Op != ONAME {
|
|
fp += fmt.Sprintf(" %v G%d", Sconv(n.Sym, 0), n.Vargen)
|
|
}
|
|
|
|
if n.Type != nil {
|
|
fp += fmt.Sprintf(" %v", Tconv(n.Type, 0))
|
|
}
|
|
|
|
if recur {
|
|
if n.Left != nil {
|
|
fp += fmt.Sprintf("%v", Nconv(n.Left, 0))
|
|
}
|
|
if n.Right != nil {
|
|
fp += fmt.Sprintf("%v", Nconv(n.Right, 0))
|
|
}
|
|
if n.List != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-list%v", Oconv(int(n.Op), 0), Hconv(n.List, 0))
|
|
}
|
|
|
|
if n.Rlist != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-rlist%v", Oconv(int(n.Op), 0), Hconv(n.Rlist, 0))
|
|
}
|
|
|
|
if n.Ntest != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-test%v", Oconv(int(n.Op), 0), Nconv(n.Ntest, 0))
|
|
}
|
|
|
|
if n.Nbody != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-body%v", Oconv(int(n.Op), 0), Hconv(n.Nbody, 0))
|
|
}
|
|
|
|
if n.Nelse != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-else%v", Oconv(int(n.Op), 0), Hconv(n.Nelse, 0))
|
|
}
|
|
|
|
if n.Nincr != nil {
|
|
fp = indent(fp)
|
|
fp += fmt.Sprintf("%v-incr%v", Oconv(int(n.Op), 0), Nconv(n.Nincr, 0))
|
|
}
|
|
}
|
|
|
|
return fp
|
|
}
|
|
|
|
// Fmt "%S": syms
|
|
// Flags: "%hS" suppresses qualifying with package
|
|
func Sconv(s *Sym, flag int) string {
|
|
if flag&obj.FmtLong != 0 /*untyped*/ {
|
|
panic("linksymfmt")
|
|
}
|
|
|
|
if s == nil {
|
|
var fp string
|
|
fp += "<S>"
|
|
return fp
|
|
}
|
|
|
|
if s.Name == "_" {
|
|
var fp string
|
|
fp += "_"
|
|
return fp
|
|
}
|
|
|
|
sf := flag
|
|
sm := setfmode(&flag)
|
|
var r int
|
|
_ = r
|
|
str := symfmt(s, flag)
|
|
flag = sf
|
|
fmtmode = sm
|
|
return str
|
|
}
|
|
|
|
// Fmt "%T": types.
|
|
// Flags: 'l' print definition, not name
|
|
// 'h' omit 'func' and receiver from function types, short type names
|
|
// 'u' package name, not prefix (FTypeId mode, sticky)
|
|
func Tconv(t *Type, flag int) string {
|
|
if t == nil {
|
|
var fp string
|
|
fp += "<T>"
|
|
return fp
|
|
}
|
|
|
|
if t.Trecur > 4 {
|
|
var fp string
|
|
fp += "<...>"
|
|
return fp
|
|
}
|
|
|
|
t.Trecur++
|
|
sf := flag
|
|
sm := setfmode(&flag)
|
|
|
|
if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
|
|
fmtpkgpfx++
|
|
}
|
|
if fmtpkgpfx != 0 {
|
|
flag |= obj.FmtUnsigned
|
|
}
|
|
|
|
var r int
|
|
_ = r
|
|
str := typefmt(t, flag)
|
|
|
|
if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
|
|
fmtpkgpfx--
|
|
}
|
|
|
|
flag = sf
|
|
fmtmode = sm
|
|
t.Trecur--
|
|
return str
|
|
}
|
|
|
|
// Fmt '%N': Nodes.
|
|
// Flags: 'l' suffix with "(type %T)" where possible
|
|
// '+h' in debug mode, don't recurse, no multiline output
|
|
func Nconv(n *Node, flag int) string {
|
|
if n == nil {
|
|
var fp string
|
|
fp += "<N>"
|
|
return fp
|
|
}
|
|
sf := flag
|
|
sm := setfmode(&flag)
|
|
|
|
var r int
|
|
_ = r
|
|
var str string
|
|
switch fmtmode {
|
|
case FErr,
|
|
FExp:
|
|
str = nodefmt(n, flag)
|
|
|
|
case FDbg:
|
|
dumpdepth++
|
|
str = nodedump(n, flag)
|
|
dumpdepth--
|
|
|
|
default:
|
|
Fatal("unhandled %%N mode")
|
|
}
|
|
|
|
flag = sf
|
|
fmtmode = sm
|
|
return str
|
|
}
|
|
|
|
// Fmt '%H': NodeList.
|
|
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
|
|
func Hconv(l *NodeList, flag int) string {
|
|
if l == nil && fmtmode == FDbg {
|
|
var fp string
|
|
fp += "<nil>"
|
|
return fp
|
|
}
|
|
|
|
sf := flag
|
|
sm := setfmode(&flag)
|
|
var r int
|
|
_ = r
|
|
sep := "; "
|
|
if fmtmode == FDbg {
|
|
sep = "\n"
|
|
} else if flag&obj.FmtComma != 0 /*untyped*/ {
|
|
sep = ", "
|
|
}
|
|
|
|
var fp string
|
|
for ; l != nil; l = l.Next {
|
|
fp += fmt.Sprintf("%v", Nconv(l.N, 0))
|
|
if l.Next != nil {
|
|
fp += sep
|
|
}
|
|
}
|
|
|
|
flag = sf
|
|
fmtmode = sm
|
|
return fp
|
|
}
|
|
|
|
func dumplist(s string, l *NodeList) {
|
|
fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
|
|
}
|
|
|
|
func Dump(s string, n *Node) {
|
|
fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
|
|
}
|